Today we’re going to keep looking at the S#arp architecture and we’re going to talk about the existing interfaces and base classes that let you work with entities. Before going on, I guess that we should define the concept of entity. According to Eric Evans’ DDD book, you’ll find that “Some objects are not defined primarily by their attributes. They represent a thread of identity that runs through time and often across distinct representations. Sometimes such an object must be matched with another object even though attributes differ. An object must be distinguished from other objects even though they might have the same attributes. Mistaken identity can lead to data corruption.”
As you can see, an entity has a very different behavior from a value object (already presented in earlier posts about this framework). With an entity, you must have some way to follow its life cycle and guarantee that every entity is uniquely identified on your system. We already have good identity management in the OO world in .NET (whenever you create a new object, you get a reference and you can use that to manage an object’s lifetime and identity).
Unfortunately, things might start to go awry when you need to mix OO life time management with persistency (generally, this means using a database, though it’s not mandatory). In this case, the default object identity you get for free from the base class is no longer enough for guaranteeing the identity of an object. If you think about persisting an object in the database, it should be fairly obvious that if you save an object and load it several times then those objects “should” be equal. You don’t get this by default in .NET because you’ll end up with different instance references on different memory positions.
The S#arp framework introduces several interfaces and base classes that you might use to help you solve these problems (as you can see from the following figure)
Lets start with the IEntityWithTypeId<T> interface:
public interface IEntityWithTypedId<IdT> {
IdT Id { get; }
bool IsTransient();
IEnumerable<PropertyInfo> GetSignatureProperties();
}
As you can see, it’s really a simple interface which lets you:
- get a value that uniquely identifies an instance (Id property). This is generally the key that uniquely identifies a persisted element in a database;
- check if an object is transient or if it has already been persisted (that’s the job of the Transient method);
- get the list of properties used for the business signature of an instance.
As you can see, this is a generic interface where the type argument identifies the type of key you’re using (I’m under the impression that most guys will go with int (System.Int32) and identity fields on the database – even though identity is broken in SQL Server).
The framework introduces a base class that implements this interface: it’s called EntityWithTypeId<T>. Besides implementing the interface, the class also extends the ValidatableObject class. Implementing the IsTransient method is really simple: you just compare the value of the private field (used for persisting the value of the Id property) with the default value of its type (ie, you check if the current value in that field equals the default(T) value).
The implementation of the GetSignatureProperties is inherited from the ValidatableObject base class, which ends up inheriting the BaseObject’s implementation. I’m sure you recall that BaseObject introduce this method in order for a class to return a collection of PropertyInfo objects which represent its business signature and relies on the template method pattern for delegating the obtaining step in a more derived class. In practice, this means that a derived class should only override the GetTypeSpecificSignatureProperties method. Let’s see the current implementation of that method in this class:
protected override IEnumerable<PropertyInfo> GetTypeSpecificSignatureProperties() {
return GetType().GetProperties()
.Where(p => Attribute.IsDefined(p, typeof(DomainSignatureAttribute), true));
}
As you can see, we use some LINQ in order to get all the properties annotated with the DomainSignatureAttribute attribute. This is just a simple marker attribute which looks like this:
[Serializable]
public class DomainSignatureAttribute : Attribute { }
The idea is that all classes that derive from EntityWithTypedId can just annotate its business signature properties with this attribute instead of overriding the GetTypeSpecificSignatureProperties method (like we did in a previous post).
The class performs one final step in order to ensure that everything works well: it overrides the Equals method. This is probably the most important thing this class does. Lets take a close look at its implementation:
public override bool Equals(object obj) {
EntityWithTypedId<IdT> compareTo = obj as EntityWithTypedId<IdT>;
if (ReferenceEquals(this, compareTo))
return true;
if (compareTo == null || !GetType().Equals(compareTo.GetTypeUnproxied()))
return false;
if (HasSameNonDefaultIdAs(compareTo))
return true;
return IsTransient() && compareTo.IsTransient() &&
HasSameObjectSignatureAs(compareTo);
}
The first lines should be self explanatory: if both elements are of the same type and point to the the same reference, then they must be equal. Now, if that isn’t the case, then several things might be happening here…
The first test that is made ensures that two objects are equal if they have the same non default ID. This means that if we have two objects that have already been persisted, then they are equal if their IDs are equal. Here’s the code for the HasSameNonDefaultIdAs method:
private bool HasSameNonDefaultIdAs(EntityWithTypedId<IdT> compareTo) {
return !IsTransient() &&
!compareTo.IsTransient() &&
Id.Equals(compareTo.Id);
}
If that test fails, then we rely on the business signature comparison inherited from the base class but only if both objects are transient!
Let’s have a quick recap on this important class:
- it has a property (Id) which is generic and is used to identify the ID you’re using to identify your object in a persistence medium;
- derived classes can use the DomainSignatureAttribute to annotate the properties that should be used in the business signature of the object;
- Equality implies doing these three tests in order: 1) do both objects point to the same reference? 2)have they been persisted and if that is the case, do they have the same signature? 3) are both objects transient and, if so, do they have the same *business* signature? whenever one of these tests returns true, the others won’t run; if none returns true, then Equals returns false;
- Since this object expands the ValidatableObject, then all EntityWithTypedId<T> instances are capable of performing validation.
We’re still missing one class: Entity. It’s objective is to set the type argument of the “open” base class to int since ints tend to be the most used types for keys in databases. Now that we’ve presented the class, it’s time for a quick example. We’re going to build in previous example, and we’re going to transform SimpleAddress into an entity:
public class SimpleAddress:Entity, IHasAssignedId<Int32> {
public SimpleAddress(String street, String zipCode ) {
Street = street;
ZipCode = zipCode;
}
[DomainSignature]
public String Street { get; private set; }
[DomainSignature]
public String ZipCode { get; private set; }
public void SetAssignedIdTo( int assignedId ) {
Id = assignedId;
}
}
Notice that we’re passing the street and zip code values through parameters to the constructor. As we’ve said before, it’s important to guarantee that business signatures don’t change and that’s why we’ve made the setters private (if those properties did change, we’d be in deep trouble if we also relied on hashes generated by the base class)
Yes, there’s also something new here: SimpleAddress implements the IHasAssignedId<T> interface. This interface has only one method (SetAssignedIdTo) which can be used for an external entity to set the Id property of the entity (notice that Id is implemented with a public getter and a protected setter on the base EntityWithTypedId<T> class). Now, if you run the next snippet:
static void Main(string[] args)
{
var address1 = new SimpleAddress( "Street X", "SomethingElse");
var address2 = new SimpleAddress("Street X","SomethingElse");
Console.WriteLine( "address1 == address2 : {0}", address1.Equals(address2));
Console.WriteLine( "address1 is transient {0}", address1.IsTransient() );
Console.WriteLine( "address1 is transient {0}", address2.IsTransient() );
//make address 1 non transient (fake it)
address1.SetAssignedIdTo( 1 );
Console.WriteLine("address1 == address2 : {0}", address1.Equals(address2));
}
You should get something like this:
And that’s it for today. Keep tuned for more on the S#arp framework.