Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling collection properties in a class and NHibernate entities

I was wondering what is the recommended way to expose a collection within a class and if it is any different from the way of doing that same thing when working with NHibernate entities.

Let me explain... I never had a specific problem with my classes exposing collection properties like:

IList<SomeObjType> MyProperty { get; set; }

Having the setter as protected or private gives me some times a bit more control on how I want to handle the collection. I recently came across this article by Davy Brion:

http://davybrion.com/blog/2009/10/stop-exposing-collections-already/

Davy, clearly recommends to have collections as IEnumerables instead of lets say Lists in order to disallow users of having the option to directly manipulate the contents of those collections. I can understand his point but I am not entirely convinced and by reading the comments on his post I am not the only one.

When it comes to NHibernate entities though, it makes much sense to hide the collections in the way he proposes especially when cascades are in place. I want to have complete control of an entity that is in session and its collections, and exposing AddXxx and RemoveXxx for collection properties makes much more sense to me.

The problem is how to do it?

If I have the entity's collections as IEnumerables I have no way of adding/removing elements to them without converting them to Lists by doing ToList() which makes a new list and therefore nothing can be persisted, or casting them to Lists which is a pain because of proxies and lazy loading.

The overall idea is to not allow an entity to be retrieved and have its collections manipulated (add.remove elements) directly but only through the methods I expose while honouring the cascades for collection persistence.

Your advice and ideas will be much appreciated.

like image 908
tolism7 Avatar asked Feb 28 '23 00:02

tolism7


1 Answers

How about...

private IList<string> _mappedProperty;

public IEnumerable<string> ExposedProperty
{
    get { return _mappedProperty.AsEnumerable<string>(); }
}

public void Add(string value)
{
    // Apply business rules, raise events, queue message, etc.
    _mappedProperty.Add(value);
}

This solution is possible if you use NHibernate to map to the private field, ie. _mappedProperty. You can read more about how to do this in the access and naming strategies documentation here.

In fact, I prefer to map all my classes like this. Its better that the developer decides how to define the public interface of the class, not the ORM.

like image 69
JulianM Avatar answered Mar 30 '23 01:03

JulianM