I want to write a rich domain class such as
public class Product
{
public IEnumerable<Photo> Photos {get; private set;}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
But the entity framework (V4 code first approach) requires an ICollection type for lazy loading! The above code no longer works as designed since clients can bypass the AddPhoto / RemovePhoto method and directly call the add method on ICollection. This is not good.
public class Product
{
public ICollection<Photo> Photos {get; private set;} //Bad
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
It's getting really frustrating trying to implement DDD with the EF4. Why did they choose the ICollection for lazy loading?
How can i overcome this? Does NHibernate offer me a better DDD experience?
I think i found the solution...See here for more details: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/47296641-0426-49c2-b048-bf890c6d6af2/
Essentially you want to make the ICollection type protected and use this as the backing collection for the public IEnumerable
public class Product
{
// This is a mapped property
protected virtual ICollection<Photo> _photos { get; set; }
// This is an un-mapped property that just wraps _photos
public IEnumerable<Photo> Photos
{
get { return _photos; }
}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
For lazy loading to work the type must implement ICollection and the access must be public or protected.
You can't insert into an IEnumerable. This applies to the EF just as much as it does to your clients. You don't have to use ICollection, though; you can use IList or other writeable types. My advice to get the best of both worlds is to expose DTOs rather than entities to your clients.
You can overcome this by using the ReadOnlyCollection(Of T)
public class Product
{
private IList<Photo> _photos;
public IList<Photo> Photos {
get
{
return _photos.AsReadOnly();
}
private set { _photos = value; }
}
public void AddPhoto(){...}
public void RemovePhoto(){...}
}
EDIT:
ICollection<T>
=> IList<T>
Hope that is what you were looking for.