-
Notifications
You must be signed in to change notification settings - Fork 25
Entity Definitions
If you recall from the section Creating Your First Entity Tree, we constructed the root node as follows:
var root = new ReadOnlyEntityTreeNode<int, Category>(c => c.CategoryId, rootItem);
The first parameter of the ReadOnlyEntityTreeNode<TId, TItem> constructor used here is a function specifying how to access the entity id from the core entity object. Internally, this constructor is actually creating an object that implements IEntityDefinition<int, Category>.
That interface is shown here:
public interface IEntityDefinition<TId, in TItem>
{
TId GetId(TItem value);
IEqualityComparer<TId> IdEqualityComparer { get; }
IEqualityComparer<TItem> AliasEqualityComparer { get; }
}
An object that implements this interface provides essential meta information about the core entity. This information is used by the tree and is the backbone of the tree's referential integrity capabilities.
A future version of TreeCollections may allow core entity types to be decorated with custom attributes which could supply this meta info. However, it was a primary design decision to not require core entity objects (or the assembly that contains them) to depend on artifacts of the TreeCollections library. Hence, the use of an interface to keep responsibilities well-focused.
So the tree node constructor we've seen so far creates an object of this type behind the scenes. It transforms the provided id access function (in this case c => c.CategoryId) into the GetId(Category item) method of the entity definition object. Beyond that, the other two properties, IdEqualityComparer and AliasEqualityComparer, are set to the default equality comparers for types TId and TItem, respectively.
As it turns out, there is a built-in EntityDefinition<TId, TItem> concrete class that implements this interface. So another way we could have constructed the root node is as follows:
var def = new EntityDefinition<int, Category>(c => c.CategoryId,
EqualityComparer<int>.Default,
EqualityComparer<Category>.Default);
var root = new ReadOnlyEntityTreeNode<int, Category>(def, rootItem);
Let's now look at the remaining two properties of the IEntityDefinition<TId, TItem> interface.
Naturally, the property IdEqualityComparer provides an IEqualityComparer<TId> so the host tree knows how to compare entity ids. In most cases, an entity id will be a primitive type so the default equality comparer of that type will suffice. However, if the id is a string, an explicit comparer may be required to take case-sensitivity into account. If the id is a class or custom struct type, an explicit comparer will be required if that type does no define its own Equals method.
An explanation of the the AliasEqualityComparer property is a bit more involved and is the subject of the next section.