Introduction
Much like other factory patterns, which allow you to create deriving objects from a base class, the Entity Factory pattern allows you to create deriving entities from a base entity or ‘element’. The element contains the rules of a particular piece of data along with a data wrapper that contains the data itself. This allows for extremely high performance when validating or analyzing an entity object.
In order to achieve this level of performance, we need to define our entities a little different than standard practices. Instead of the property getters and setters working with a private field within the entity class, ‘rule’ fields work with a Hashtable within the BaseHash
class and ‘entity’ fields work with the Elements
collection within the EntityAbstract
class. It’s not a difficult adjustment to make and well worth the effort. In addition to performance, this pattern offers a simple way to maintain data constraints across all your applications.
UML Class Diagram
The BaseHash Class
When casting one entity to another, the property values are not populated in the new entity. This can be overcome by including a constructor in the deriving class that accepts an instance of the base class as a parameter. The deriving class then passes the parameter to a constructor on the base class.
public ElementBaseData(ElementBase elementBase) : base(elementBase)
public ElementBase(ElementBase elementBase)
Within the base class constructor, you can either hard code the fields to be set to the values of the parameter or use Reflection to iterate through the fields in the parameter and populate the corresponding fields in the new object. The first option is very fast, but also very rigid. The latter option gives you the generic flexibility, but is very slow. Not only slow, reflection will slow down disproportionately to the first approach, as more fields are added.
Benchmarks (100k iterations)
1 field
| 10 fields
|
Hard Coded ~20ms | Hard Coded ~50ms |
Reflection ~500ms | Reflection ~2800ms |
By using a Hashtable
to manage the field values, we can get the best of both approaches. Now, the constructor on our ElementBase
looks like this.
public ElementBase(ElementBase elementBase)
{
Hash = elementBase.Hash;
}
Our benchmarks come in a little higher than the hard coded approach (1 field = ~110ms), but as the number of fields grow, the hash approach is able to handle it more efficiently than either of the other approaches (10 fields = ~210ms). Ten fields in less than two times the duration of one field.
To begin, we’ll need to create our BaseHash
class. This simply consists of a property with a Hashtable
type and a method called InitializeProperties
. The purpose of the InitializeProperties
method will be shown in the next section; The ElementBase
Class.
public class BaseHash
{
private Hashtable _hash = new Hashtable();
public BaseHash()
{
}
public Hashtable Hash
{
get { return _hash; }
set { _hash = value; }
}
protected void InitializeProperties(Type enumerator)
{
int i = 0;
Enum.GetNames(enumerator).ToList().ForEach(e => _hash.Add(i++, null));
}
}
The ElementBase Class
Data constraints are stored in-process on the ElementBase
class. The example below contains only a small subset of fields. You may have additional requirements for your constraints like ‘IsNumeric
’ or ‘MatchCode
’. You can simply add these properties to the ElementBase and define their behavior in the ElementBaseData
class. For simplicity, I’m only going to create a few fields.
Notice the way the property getters and setters are written in the example below. They work against the Hashtable
in BaseHash
rather than private fields. This will give us the speed and flexibility mentioned in the previous section. We need to initialize the properties when the instance is created. Otherwise, we will get errors from the property, because the index has not been setup in the Hashtable.
public class ElementBase : BaseHash, IBase
{
public enum ElementBaseFields : int
{
ID,
Name,
MaxLength,
MinLength
}
public ElementBase()
{
InitializeProperties(typeof(ElementBaseFields));
}
public ElementBase(ElementBase elementBase)
{
Hash = elementBase.Hash;
}
[DataMember]
public int? ID
{
get
{
if (Hash[(int)ElementBaseFields.ID] == null)
return null;
return int.Parse(Hash[(int)ElementBaseFields.ID].ToString());
}
set { Hash[(int)ElementBaseFields.ID] = value; }
}
[DataMember]
public string Name
{
get
{
if (Hash[(int)ElementBaseFields.Name] == null)
return null;
return Hash[(int)ElementBaseFields.Name].ToString();
}
set { Hash[(int)ElementBaseFields.Name] = value; }
}
[DataMember]
public int? MaxLength
{
get
{
if (Hash[(int)ElementBaseFields.MaxLength] == null)
return null;
return int.Parse(Hash[(int)ElementBaseFields.MaxLength].ToString());
}
set { Hash[(int)ElementBaseFields.MaxLength] = value; }
}
[DataMember]
public int? MinLength
{
get
{
if (Hash[(int)ElementBaseFields.MinLength] == null)
return null;
return int.Parse(Hash[(int)ElementBaseFields.MinLength].ToString());
}
set { Hash[(int)ElementBaseFields.MinLength] = value; }
}
}
The ElementBaseData Class
The ElementBaseData
is a data wrapper for the ElementBase
. Here we can create our Data
property in the traditional way. We’ll make a private variable object field called _data
and make a property called Data
that uses it.
One important thing to consider with this pattern is cloning. If we we’re to just clone this item, it would continue to share the Hashtable with the originator. This could cause big problems. It’s important to include a Clone
method that will also clone the Hashtable for us.
I’ve also included a Validation
method. This will demonstrate the high performance we get from this pattern. You can see how we make use of the properties exposed in the ElementBase to perform our validation.
The exceptions exposed by the Validation method are strings rather than Exception objects. Since the problem isn’t from the stack, there’s no need for the overhead of an Exception object.
public class ElementBaseData : ElementBase, IBaseData, ICloneable
{
private object _data = null;
public ElementBaseData() : base()
{
}
public ElementBaseData(ElementBase elementBase)
: base(elementBase)
{
}
[DataMember]
public object Data
{
get { return _data; }
set { _data = value; }
}
[OperationContract]
public object Clone()
{
ElementBaseData elementBaseData = this.MemberwiseClone() as ElementBaseData;
elementBaseData.Hash = Hash.Clone() as Hashtable;
return elementBaseData;
}
[OperationContract]
public List<string> Validate()
{
List<string> exceptions = new List<string>();
if (MaxLength != null && _data.ToString().Length > MaxLength)
exceptions.Add(String.Format("Property: {0}{1}{2}", Name, Environment.NewLine, "Data is too long"));
if (MinLength != null && _data.ToString().Length < MinLength)
exceptions.Add(String.Format("Property: {0}{1}{2}", Name, Environment.NewLine, "Data is too short"));
return exceptions;
}
}
The EntityAbstract Class
Now we’re ready to create our abstract class for our entities. The properties values of our entities will be stored and retrieved from the Elements
property on the EntityAbstract
. The Elements
property is a collection of ElementBaseData
objects. The other property on the EntityAbstract
is the Exceptions
property. This is a collection of exception strings generated by the Validation method on the ElementBaseData
objects.
We run into the same cloning issue that we saw in the ElementBaseData
class. To avoid sharing the same collection of elements, we will need to have a Clone
method that will clone the elements for us too. Also, in the EntityAbstract
class, we’ll want to create a Validation method. This will give each of our entities the functionality for quick validation of all the elements within the entity. After validating, we can call the Exceptions
property to get any exceptions that were generated.
public abstract class EntityAbstract : ICloneable
{
private List<ElementBaseData> _elements = new List<ElementBaseData>();
private List<string> _exceptions = new List<string>();
public List<ElementBaseData> Elements
{
get { return _elements; }
set { _elements = value; }
}
public List<string> Exceptions
{
get { return _exceptions; }
set { _exceptions = value; }
}
public virtual object Clone()
{
List<ElementBaseData> elements = new List<ElementBaseData>();
Elements.ForEach(e => elements.Add(e.Clone() as ElementBaseData));
return elements;
}
public virtual bool Validate()
{
Exceptions.Clear();
return Elements.FindAll(e => !Validate(e)).Count == 0;
}
private bool Validate(ElementBaseData elementBaseData)
{
List<string> elementExceptions = elementBaseData.Validate();
elementExceptions.ForEach(ex => _exceptions.Add(ex));
return elementExceptions.Count == 0;
}
}
Entity Classes and the ElementIndex
The ElementIndex
is an in-process repository of element rules. In this example I use a static class, but a Singleton will work just as well. If you need to track usage or want to load balance the ElementIndex, you’ll need to use the Singleton Pattern. These aren’t needed for this demonstration, so I choose to show the static class to keep it simple.
One nice feature of the ElementIndex
is that it allows you to maintain your data standards across entities and systems. For example, you may have a system that can accept last names that are 25 characters long and have a different system that can accept last names that are 35 characters long. With the ElementIndex
you can make sure the least common denominator is always used and avoid truncation after the data is collected.
public static class ElementIndex
{
public readonly static ElementBase FirstName = new ElementBase()
{
Name = "First Name",
MinLength = 1,
MaxLength = 25
};
public readonly static ElementBase LastName = new ElementBase()
{
Name = "Last Name",
MinLength = 1,
MaxLength = 25
};
public readonly static ElementBase Age = new ElementBase()
{
Name = "Age",
MinLength = 1,
MaxLength = 3
};
}
Now we can begin creating our entities. For this demonstration I will create a TestEntity
class extending the EntityAbstract
. In the constructor I will add each field to the Elements property of the EntityAbstract
. The field is an ElementBaseData
object built from an ElementBase
that is defined in the ElementIndex
. Next, I create a property for each element that I have created in the constructor.
Again, I need to consider the clone method. I can handle this by overriding the base clone while still using the base method to rebuild my elements collection.
public class TestEntity : EntityAbstract
{
public enum TestEntityFields : int
{
FirstName,
LastName,
Age
}
public TestEntity()
{
Elements.Add(new ElementBaseData(ElementIndex.FirstName)
{
ID = (int)TestEntityFields.FirstName
});
Elements.Add(new ElementBaseData(ElementIndex.LastName)
{
ID = (int)TestEntityFields.LastName
});
Elements.Add(new ElementBaseData(ElementIndex.Age)
{
ID = (int)TestEntityFields.Age
});
}
public string FirstName
{
get { return Elements[(int)TestEntityFields.FirstName].Data.ToString(); }
set { Elements[(int)TestEntityFields.FirstName].Data = value; }
}
public string LastName
{
get { return Elements[(int)TestEntityFields.LastName].Data.ToString(); }
set { Elements[(int)TestEntityFields.LastName].Data = value; }
}
public int Age
{
get { return int.Parse(Elements[(int)TestEntityFields.Age].Data.ToString()); }
set { Elements[(int)TestEntityFields.Age].Data = value; }
}
public override object Clone()
{
List<ElementBaseData> elements = base.Clone() as List<ElementBaseData>;
TestEntity testEntity = this.MemberwiseClone() as TestEntity;
testEntity.Elements = elements;
return testEntity;
}
}
Testing the Pattern
I’ve put together a simple console application to test and benchmark the performance of our pattern. It will iterate through the elements in our TestEntity class, asking the user for inputs on each. Once all the inputs are collected, it will perform a validation 1,000 times and report the duration in milliseconds. It will also report whether the data is valid or display all the errors that it encountered.
class Program
{
private static void GetUserInput(ElementBaseData elementBaseData)
{
Console.Write(String.Format("{0}: ", elementBaseData.Name));
elementBaseData.Data = Console.ReadLine();
}
static void Main(string[] args)
{
while(true)
{
TestEntity testEntity = new TestEntity();
testEntity.Elements.ForEach(e => GetUserInput(e));
System.Diagnostics.Stopwatch bench = new System.Diagnostics.Stopwatch();
bench.Start();
int iEnd = 1000;
for (int i = 0; i < iEnd; i++)
{
testEntity.Validate();
}
bench.Stop();
Console.WriteLine(String.Format("Validated {0} times in {1} milliseconds.",
iEnd.ToString(), bench.ElapsedMilliseconds.ToString()));
if (testEntity.Validate())
Console.WriteLine("Data is valid");
else
testEntity.Exceptions.ForEach(ex => Console.WriteLine(ex));
}
}
}
Conclusion
This pattern offers two major advantages; high performance and the ability to consolidate your constraint variables. It also creates a framework, ready for more advanced functionality like persistence and reporting.
Although we’re changing the way the getters and setters are working with their values, the properties and methods of the entities are still exposed the same way traditional entities expose their members. This will allow you to continue using Interfaces and LINQ to Entities as you have before. Any Reflection that uses GetField will need to be modified to use the Elements property. This will give you much better performance.
In my next article, I will demonstrate using a Memento Pattern that integrates perfectly with the Entity Factory Pattern giving your applications 'Ctrl-Z', 'Ctrl-Y' functionality.