I am testing how difficult it is to use NHibernate with a domain that is completely unaware of this and is not inclined to adapt any restrictions.
In many examples that I found on the Internet, the display domain is another example of an anemic domain where objects are not far from simple data carriers. Sure, this makes the display simple and all, and it may appeal to data-oriented characters / situations, but I don’t like hearing voices in my head that say “C also has structures, you know?”, “Classes don't are just knowledgeable namespaces, you know? " or "Why don't you use CREATE TABLE?".
But back to NHibernate. NHibernate forces me to make properties virtual so they can proxy them for lazy loading. This is something that I do not mind, because they may need them as virtual for some AOP subjects. Limitations that do not suit me are the need for an empty constructor and the need for settings / properties. I want my objects to be created in the correct state, and most of the time this means that there is no empty constructor. I also do not want to expose setters for collection properties for the usual reasons. Oh, and setters for attributes that should not be changed directly.
Consider this simplified and far-fetched set in the domain model:
public class ShoppingCartItem
{
private readonly Product product;
public ShoppingCartItem(Product product, int quantity)
{
if(quantity <= 0)
throw new ArgumentOutOfRangeException("quantity");
this.product = product;
this.quantity = quantity;
}
public virtual Product Product
{
get { return product; }
}
private int quantity;
public virtual int Quantity
{
get { return quantity; }
set
{
if(value <= 0)
throw new ArgumentOutOfRangeException("value");
quantity = value;
}
public virtual Money TotalPrice
{
get { return product.Price * quantity; }
}
}
public class ShoppingCart : Entity
{
private readonly IDictionary<Product, ShoppingCartItem> items =
new Dictionary<Product, ShoppingCartItem>();
private readonly ISet<DiscountCoupon> discountCoupons =
new HashSet<DiscountCoupon>();
public virtual IEnumerable<ShoppingCartItem> Items
{
get { return items.Values; }
}
public virtual IEnumerable<DiscountCoupon> DiscountCoupons
{
get { return discountCoupons; }
}
public virtual void AddProduct(Product product)
{
ShoppingCartItem item;
if(items.TryGetValue(product, out item))
item.Quantity++;
else
items.Add(product, new ShoppingCartItem(product, 1));
}
public virtual void RemoveProduct(Product product)
{
ShoppingCartItem item;
if(!items.TryGetValue(product, out item))
throw new ArgumentException("product");
if(item.Quantity == 1)
items.Remove(product);
else
item.Quantity--;
}
public virtual int AddDiscountCoupon(DiscountCoupon coupon)
{
discountCoupons.Add(coupon);
}
public virtual int RemoveDiscountCoupon(DiscountCoupon coupon)
{
discountCoupons.Remove(coupon);
}
public virtual Money CalculatePrice()
{
return items.Values.Sum(item => item.TotalPrice);
}
}
, . , . NHibernate ? ? ?