Wrox Programmer Forums

Need to download code?

View our list of code downloads.

| FAQ | Members List | Search | Today's Posts | Mark Forums Read
BOOK: Professional ASP.NET Design Patterns
This is the forum to discuss the Wrox book Professional ASP.NET Design Patterns by Scott Millett; ISBN: 978-0-470-29278-5
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional ASP.NET Design Patterns section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developers’ questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Search this Thread Display Modes
  #1 (permalink)  
Old September 19th, 2011, 02:41 PM
Registered User
Points: 11, Level: 1
Points: 11, Level: 1 Points: 11, Level: 1 Points: 11, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2011
Posts: 3
Thanks: 0
Thanked 1 Time in 1 Post
Default AggregateRoot

This is an excellent book. I've been telling my friends they must read this book! I've read the entire book a couple of times and learn something from every chapter.

There is one topic I haven't been able to completely understand with respect to one issue, and that's managing grandchildren through an AggregateRoot. The examples in the book make it clear how to manage immediate children through the AggregateRoot, but it's unclear to me how one might expand this pattern to add/update/delete a grandchild.

Would you please share your thoughts on how you would accomplish this?

Thank you
Reply With Quote
  #2 (permalink)  
Old September 20th, 2011, 08:35 AM
elbandit's Avatar
Wrox Author
Points: 599, Level: 8
Points: 599, Level: 8 Points: 599, Level: 8 Points: 599, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2007
Location: Southsea, Portsmouth, Hampshire, United Kingdom.
Posts: 107
Thanks: 10
Thanked 17 Times in 15 Posts
Default

Hi Scook,

Thanks for you kind words and thanks for buying the book!

Like all good software answers it depends on the context! Do you have a particular context/example in mind?

Cheers
Scott
Reply With Quote
  #3 (permalink)  
Old September 20th, 2011, 01:36 PM
Registered User
Points: 11, Level: 1
Points: 11, Level: 1 Points: 11, Level: 1 Points: 11, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Sep 2011
Posts: 3
Thanks: 0
Thanked 1 Time in 1 Post
Default

I guess I’m fundamentally hung up on the motivational points that determine whether to include a particular domain entity in an aggregation. When I read your definition for Aggregates and Aggregate Roots, I got the impression that the pattern could manage a deep graph of related objects; beyond a parent-child relationship where the aggregate root would have a method to add a child to an internal list and enforce any business rules regarding its addition to the list.

I started to create an exploratory project to test out all these patterns after being sold on the value of repositories in respect to unit-of-work, mock repositories for unit testing, and encapsulating data store details. I modeled a training log program where a user could create a triathlon program. In my model I had
TrainingLog : IAggregateRoot
1 -> *
TrainingDay
1 -> *
Entry – since one will train more than one sport in a day.
1 -> 1 (Scheduled) and 1 -> 1 (Performed)
Activity – contained in Entry as value objects: Scheduled and Performed.
1 -> *
Lap – a list in Scheduled and Performed.

Initially, I was thinking that the referential constraints and business rules enforced in a database model would determine which entities are grouped together in an aggregation. Since it didn’t make sense to have any of the domain entities below the TrainingLog remain in the db if the parent was deleted, it seemed that graph would be an aggregation. If one were to implement this aggregation, I do not see how one would add an Entry or a Lap through a method in the TrainingLog aggregate root. I realize this example does not have biz rules to validate the addition of child entities at any level, so one could make TrainingDay and Entry aggregate roots in separate repositories and avoid the technical obstacle. But what if there were rules and one had to manage them through the TrainingLog root.

There also seems to be counter forces to including domain entities in an aggregation. It seems that an entire aggregation is loaded, so if any part needs to be lazy-loaded or if any part needs to be filtered, then it needs to become an aggregate root in a separate repository.
Reply With Quote
  #4 (permalink)  
Old September 20th, 2011, 02:09 PM
elbandit's Avatar
Wrox Author
Points: 599, Level: 8
Points: 599, Level: 8 Points: 599, Level: 8 Points: 599, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2007
Location: Southsea, Portsmouth, Hampshire, United Kingdom.
Posts: 107
Thanks: 10
Thanked 17 Times in 15 Posts
Default

Hi Scook,

How about something like....

var training_schedule = _gym_members_training_schedules.find_by(membership _id);
//gym members training schedule is the repository

//schedule an activity
training_schedule.schedule_training_for(date_for_a ctivity, activity);

//update activity with laps achieved
var days_activities = training_schedule.get_scheduled_training_for(date_ of_activity).

days_activities.for(activity_completed).set_laps_c ompleted_to(4);

Does that make sense?

Cheers
Scott

Last edited by elbandit; September 20th, 2011 at 02:17 PM..
Reply With Quote
  #5 (permalink)  
Old December 5th, 2011, 08:48 AM
Registered User
Points: 23, Level: 1
Points: 23, Level: 1 Points: 23, Level: 1 Points: 23, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Dec 2011
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default Aggregate Root and Many To Many Tables

Hello,

I have an issue when trying to add an entity to another entity and saving the parent entity. I have three classes, customer, address and contact. Address and Contact have a many to many relationship.

I am using your EntityBase class on all three classes and the Customer class implements IAggregateRoot but the address and contact classes don't.

Below is the code I am using.

Code:
Dim lscustomers As List(Of Customer) = _customerRepository.Find(2).ToList
Dim customerInst As New Customer

If (lscustomers.Count > 0) Then
    Dim contactInst As New Contact
    contactInst = request.ContactView.ConvertToContact

    Dim addressInst As Address = request.AddressView.ConvertToAddress
    addressInst.AddContact(contactInst)

    customerInst = lscustomers.FirstOrDefault
    customerInst.AddAddress(addressInst)

    addResponse.BrokenRules = customerInst.GetBrokenRules()
End If

_customerRepository.Save(customerInst)
_uow.CustomerCommit()

When I use the above code I receive the following error message.

Unable to cast object of type 'PDS.PDSOS.Model.Models.Customers.Address' to type 'PDS.PDSOS.Model.Models.Customers.Contact'

But if I do not add the contact object to the address object it then saves correctly.

Can I save multiple levels of objects and only save the top level object *customer* to the DB.
Or do I have to save the address object seperately which has the contact object inside it? So I end up with the following.

_customerRepository.Save(customerInst)
_addressRepository.Save(addressInst)
Reply With Quote
  #6 (permalink)  
Old December 5th, 2011, 11:18 AM
Registered User
Points: 23, Level: 1
Points: 23, Level: 1 Points: 23, Level: 1 Points: 23, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Dec 2011
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hello,

Can you tell me the benefit of the code below inside EntityBase please?

Code:
Public Overrides Function Equals(entity As Object) As Boolean
            Return entity IsNot Nothing AndAlso TypeOf entity Is EntityBase(Of TId) AndAlso Me = DirectCast(entity, EntityBase(Of TId))
        End Function

        Public Overrides Function GetHashCode() As Integer
            Return Me.Id.GetHashCode()
        End Function

        Public Shared Operator =(entity1 As EntityBase(Of TId), entity2 As EntityBase(Of TId)) As Boolean
            If DirectCast(entity1, Object) Is Nothing AndAlso DirectCast(entity2, Object) Is Nothing Then
                Return True
            End If
            If DirectCast(entity1, Object) Is Nothing OrElse DirectCast(entity2, Object) Is Nothing Then
                Return False
            End If
            If entity1.Id.ToString() = entity2.Id.ToString() Then
                Return True
            End If
            Return False
        End Operator

        Public Shared Operator <>(entity1 As EntityBase(Of TId), entity2 As EntityBase(Of TId)) As Boolean
            Return (Not (entity1 = entity2))
        End Operator
Reply With Quote
  #7 (permalink)  
Old December 5th, 2011, 11:33 AM
elbandit's Avatar
Wrox Author
Points: 599, Level: 8
Points: 599, Level: 8 Points: 599, Level: 8 Points: 599, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2007
Location: Southsea, Portsmouth, Hampshire, United Kingdom.
Posts: 107
Thanks: 10
Thanked 17 Times in 15 Posts
Default

Hi Mike,

In DDD entities should be comparable only on there id and not be there attributes. (see DDD http://domaindrivendesign.org/node/109)

Here is a good post on overrideing equality and comparing entities.

http://nathan.whiteboard-it.com/arch...sign-deux.aspx

I will reply to your post in a bit.

Cheers
Scott
Reply With Quote
  #8 (permalink)  
Old December 5th, 2011, 12:37 PM
elbandit's Avatar
Wrox Author
Points: 599, Level: 8
Points: 599, Level: 8 Points: 599, Level: 8 Points: 599, Level: 8
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: May 2007
Location: Southsea, Portsmouth, Hampshire, United Kingdom.
Posts: 107
Thanks: 10
Thanked 17 Times in 15 Posts
Default

Hi Mike,

I can't be sure but it looks like Customer is your Aggregate Root. An aggregate root acts as a consistency boundary to a set of related entities/value objects. If you have your mapping set up ok you should only need to save the aggregate root and all of the children will be saved along with it. e.g. you should be able to do this....

Code:
var customer  = _customer_repository.find_by(id);

customer.add_contact(new Contact());

_customer_repository.save(customer  )
_uow.CustomerCommit()
I am not sure about your error without looking at your code, can you email it or put it up on github?

Cheers
Scott
Reply With Quote
  #9 (permalink)  
Old December 5th, 2011, 12:43 PM
Registered User
Points: 23, Level: 1
Points: 23, Level: 1 Points: 23, Level: 1 Points: 23, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Dec 2011
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hello Scott,

Thank you for your reply.

The Customer object is my Aggregate Root and I am adding an address to the customer and a contact to the address and then saving the customer object.

I have done some debugging and from looking at the link you sent me I was able to modify the = method inside entity base to add a reference check inside where it compares both entities Id's. I am using the code below.

Code:
If entity1.Id.ToString() = entity2.Id.ToString() Then
                If (ReferenceEquals(entity1, entity2)) Then
                    Return True
                Else
                    Return False
                End If
            End If
By using the reference check that has allowed the object to save correctly.

Thank you.
Reply With Quote
  #10 (permalink)  
Old December 6th, 2011, 05:20 AM
Registered User
Points: 23, Level: 1
Points: 23, Level: 1 Points: 23, Level: 1 Points: 23, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Dec 2011
Posts: 7
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hello Scott,

I did have another question about using IAggregateRoot.

I have a customer table and it has a column called CustomerStatus which links to a customerStatus table.

At the moment I have my customer object as IAggregateRoot and not the CustomerStatus object because the CustomerStatus will be part of the customer when the customer is saved to the database.

However I also have an admin area and I can add/delete/update a customer status. Because I have this admin area for customer status do I need to have the customer status object as an IAggregateRoot because I will only be saving this object to the database from the admin area as it has nothing to do with the customer object?

If I do have customer status as an IAggregateRoot, how does this work with the customer object that is also an IAggregateRoot?

Thank you.

Mike
Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off




All times are GMT -4. The time now is 11:17 AM.


Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.