Friday, October 8, 2010

Entity Framework and Max Field Length

Being able to check the maximum length of an entity field can be incredibly useful. Later, I'll be exploring how to automatically validate entity lengths, but for the moment we just need to find them. Worry about using them for later post.

Entity Framework 4 Data Models, edmx files, provide all the database metadata, but it takes a bit of finding. First, you need a valid ObjectContext. I'm using the Repository/UnitOfWork pattern and my UnitOfWork acts as a wrapper around the ObjectContext that gets passed into the repositories. At the moment the functionality to check length is in the UnitOfWork, but can reasonably be moved anywhere that has access to the database context, such as the repository base. Might make more sense there even.

Anyways, to the code. There are several examples around the web and they provided starting points on where to find the correct metadata. In the end, the code is actually quite short.

/// <summary>
/// Find the maximum length of an entity field in this context
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
public int Length<TEntity>(string field)
{
    var item = Context.MetadataWorkspace.GetItem<EntityType>(typeof(TEntity).FullName, DataSpace.CSpace);
    return (int)item.Properties[field].TypeUsage.Facets["MaxLength"].Value;
}

I leave error checking to be handled by the caller. The only errors that should be thrown are if the Context is invalid, ArgumentExceptions if you send an invalid entity, field name, or perhaps most importantly, you try to run this against a non-string type like int or bool.

To explain a bit of the code, you need access to the MetadataWorkspace. I believe that ADO.Net and Linq to SQL all create this object and provide access to it one way or another. From there, you can get EntityType metadata. Other examples online pulled all the entities, but that isn't really necessary. The GetItem function works fine. If the TEntity typ is invalid, this function will throw an error. Once we have the EntityType item, we have the full info about that particular tracked entity, and within the Properties, we can get field data. There are other Facets available depending on the data type. Strings contain these:

  • Nullable
  • DefaultValue
  • MaxLength
  • Unicode
  • FixedLength

So it would be pretty easy to rework this function to provide any one of those meta values.

The TEntity type should be a valid model type tracked by the context, and the field is just a property name. There's probably some fancy-dancy reflection way to eliminate the string here, but I haven't found it yet.

Calling the function looks something like this:

int length = _unitOfWork.Length<User>("UserName");

Again, placing this in the UnitOfWork might not make the best sense. Perhaps in a Repository which contains an actual ObjectSet would be a bit safer.

It should be noted that for other data types, int, bool, floats, etc., different Facets are available, and for some, trying to reference MaxLength will result in an exception being thrown. More information about the actual field type can be found in EntityType.Properties([field]).TypeUsage.EdmType. Greater error checking can, and probably shoud, be put in place.

No comments:

Post a Comment