Reputation: 4786
This answer indicates that the best way to prevent public accessible modification of collection contents is to only expose the enumerable of the collection.
However, I don't think this is possible when using Entity Framework to hydrate the collections from a backing database as this calls the empty constructor and assigns the properties.
Is there a way around this?
Upvotes: 0
Views: 31
Reputation: 34698
Not specifically. The pattern I use is to mark setters as internal
and use public mutator methods to handle updates. This does not restrict modification of things like the entity collections (which need to be ICollection<T>
at a minimum) but if it provides a standard and easy to follow path, then trust that all developers will use it.
The pattern for collections would be:
public virtual ICollection<Child> Children { get; internal set; } = new List<Child>();
Nothing prevents code interacting with the Children collection from doing .Children.Add(new Child { /* ... */ });
however, if my parent class offers:
public Child AddChild(string Name, DateTime dob /*, ... */)
{
// TODO: Validate passed in parameters, look for duplicates, etc...
var child = new Child{ /* ... */, Parent = this };
Children.Add(child);
return child;
}
... then it's pretty easy to do a Find Usages on things like child collections or noticing that the provided Add methods aren't used and raising this with the other developers if they are deviating from the pattern. The benefit of mutators is that it ensures that everything needed is provided so the resulting object can be trusted as complete and valid. It doesn't force developers to use the mutator methods, but it saves them from worrying about incomplete state and having to explain why they chose not to use it. Trying to rigidly enforce a pattern can be difficult and can end up making your code base inflexible and miss out on many of the benefits a technology like EF can provide. Good patterns should be promoted on their own merits of making life easier for developers.
Ultimately the key thing I aim to avoid is not passing entities around beyond the boundary of the code responsible for the DbContext scope. I.e. if I'm dealing with a Presentation layer and a Service layer where the Service interacts with the domain via EF entities, then the service does not pass entities to the presentation. (which might want to ultimately manipulate the domain) Instead, the presentation layer can be given POCO View Models or DTOs with more rigid constraints to work with, then pass those back to the Service to deal with the entities. This way, outside the boundary of the entities can be more tightly constrained without compromizing EF capabilities. (I.e. leveraging navigation properties in Linq expressions)
Upvotes: 1