O/R Mappers, the Law of Demeter, and Lazy Loading
Basically, my argument was that writing orderLine.Product.Price coupled your code with the object model structure, so I suggested it was better to write orderLine.ProductPrice.
This idea is not new, and is called the Law of Demeter.
One of the reasons I disliked O/R mappers was because, in my opinion, they forced you to write code such as orderLine.Product.Price. However, that's not necessarily true. A good O/R mapper should let you map the orderLine.ProductPrice to any field in the database that can be retrieved knowing the orderLine primary key.
For example, if the Price is not stored in the Product table but in a table that relates Customer and Product (to have a different price for each Customer), I can retrieve the product price from the OrderLine by using orderLine.Order.Customer.Id + orderLine.Product.Id to read CustomerProduct.Price.
Note that if I write orderLine.Product.Price and then the product price depends on the customer, there's no way to hide that. I cannot make Product.Price return the customer's price because I cannot obtain the 'Customer.Id' from the Product.
I don't know which O/R mappers support creating this mapping directly. But I do know Hibernate (a well-known Java O/R mapper) does not.
Of course, with any O/R mapper you can manually write the orderLine.ProductPrice to do something like the following:
public decimal ProductPrice
{
get
{
return CustomerProductFactory.Get(this.Order.Customer.Id, this.Product.Id).Price;
}
}
This way, you are not solving the problem at the mapping level but in the code.
Why do I think it's important to solve this at the mapping level? Because it's a good way to know when you need to eager load or to lazy load.
You are not going to add 'shortcut' properties in your classes for every reachable field. For example, if I'm not using the Product.Category.Name in the Order, then I won't have a CategoryName field in it.
If I add the shortcut, it’s because the field is relevant to the Order. So I can assume that if it's relevant to the order, it should be eager loaded.
In sum, if you want to apply the Law of Demeter to your domain model and your persistence layer, you should never write object.object.property, and you should use the shortcuts to know what to eager load.
If you know any O/R mapper that supports this at the mapping level, please let me know.
This is what we’ve always done with DeKlarit, but we are not an O/R mapper. In this case, we load DataSets with all the fields that are relevant to an Order, regardless of where they are stored.