Note that there are some explanatory texts on larger screens.

plurals
  1. POIs a Person an aggregate root?
    text
    copied!<p>Since all entities have a stamped of who created/modified the record, can we consider a Person entity an aggregate root to all entities?</p> <p>That is, all entities that references the Person will become a collection to Person, e.g.</p> <pre><code>public class Person { public virtual int PersonId { get; set; } public virtual string Lastname { get; set; } public virtual IList&lt;OrderHeader&gt; CreatedOrders { get; set; } public virtual IList&lt;OrderHeader&gt; ModifiedOrders { get; set; } // Other entities that have a reference on Person will be mapped as a collection under // the Person entity } public class OrderHeader { public virtual int OrderId { get; set; } public virtual DateTime OrderDate { get; set; } public virtual Customer Customer { get; set; } public virtual string CommentsOnThisOrder { get; set; } // stamp audit-level concerns public virtual Person CreatedBy { get; set; } public virtual DateTime DateCreated { get; set; } public virtual Person ModifiedBy { get; set; } public virtual DateTime DateModified { get; set; } public virtual IList&lt;OrderItem&gt; OrderItems { get; set; } } public class OrderItem { public virtual OrderHeader OrderHeader { get; set; } public virtual Product Product { get; set; } public virtual int Quantity { get; set; } public virtual decimal Price { get; set; } } </code></pre> <p>That will basically make all entities become a collection to Person, which violates DDD aggregate root rules.</p> <p>In my limited understanding of DDD aggregrate, the OrderHeader must not become a collection to Person, as we should not save the Order aggregate via Person. The only <strong>*entry*</strong> point for saving the Order aggregate(object graph) must be done from the OrderHeader, not from the Person.</p> <p>Now here comes my real goal even why it looks dirty, I still wanted the Order to be a collection to Person: </p> <p>There's one ORM *cough* NHibernate *cough* that cannot do a LEFT JOIN (.DefaultIfEmpty) from Person to OrderHeader if OrderHeader is not mapped as a collection to Person. The only way to achieve LEFT JOIN from Person to OrderHeader is to map the OrderHeader as a collection to Person.</p> <p>Should I allow infrastructure concerns (e.g. <a href="https://github.com/nhibernate/nhibernate-core/commit/93a30501a8b72ce79a63455f0e44b28fb575733a" rel="nofollow">facilitating</a> LEFT JOIN from Person to OrderHeader via Linq's .DefaultIfEmpty by making the OrderHeader become a collection to Person) break the rules on when should only an entity must become an aggregate root?</p> <p>If we will not map the OrderHeader as a collection to Person, then if we needed to make a LEFT JOIN (flattened result, not hierarchical, hence the need to use LEFT JOIN) from Person to OrderHeader on NHibernate, the only option left is to use QueryOver. QueryOver is very tedious to write compared to Linq.</p> <p>Cannot use the .DefaultIfEmpty(LEFT JOIN functionality) on NHibernate's Linq if we manually do a LEFT JOIN (i.e., via Linq's join and .DefaultIfEmpty) from Person to OrderHeader, .DefaultIfEmpty throws an exception if we do a manual LEFT JOIN on NHibernate, LEFT JOIN on NHibernate's Linq must be done via collection and .DefaultIfEmpty.</p> <p>If done occasionally(per need-basis), is breaking the rules on aggregate root a pragmatic choice? Example, should I map the OrderHeader as collection to Person in order to facilitate LEFT JOIN from Person to OrderHeader via Linq?</p> <p><strong>EDIT</strong></p> <p>Sample northwind database. When we need to report all customers with their orders including those customers without orders(e.g., PARIS)</p> <pre><code> CustomerID OrderID OTTIK | 10407 OTTIK | 10684 OTTIK | 10554 PARIS | PERIC | 10502 PERIC | 10474 PERIC | 10995 PERIC | 10354 PERIC | 11073 PERIC | 10322 </code></pre> <p>, we need to do a LEFT JOIN:</p> <pre><code>select c.CustomerID, o.OrderID from customers c left join orders o on c.CustomerID = o.CustomerID order by c.CustomerID </code></pre> <p>That can be done with Linq's join and .DefaultIfEmpty(). However NHibernate's Linq can't do a .DefaultIfEmpty on the result of manual Linq join, it throws an exception. NHibernate's DefaultIfEmpty can only be applied on a collection. But I feel mapping a collection to something that is not an aggregate root violates DDD aggregate root rules. And also doing so, all entities such as Person (Customer is another example) will potentially contain collections of <em>ALL</em> entities, as every table has a CreatedByPerson reference.</p> <p>@DanielSchilling:</p> <p>I'm also surprised(in a good way), that referencing the OrderHeader from OrderItem violates DDD. Do we have some sort of whitepaper or a Martin Fowler article expounding on that? I thought referencing a parent entity from a child entity is not considered an infrastructure concern, thus considered DDD.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload