Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

NHibernate Conventions

Introduction

It seems that nowadays everyone loves conventions! Not the ones that you go to, but the ones that you use, that is! It just happens that NHibernate also supports conventions, and we’ll see exactly how.

Conventions in NHibernate are supported in two ways:

  • Naming of tables and columns when not explicitly indicated in the mappings;
  • Full domain mapping.

Naming of Tables and Columns

Since always NHibernate has supported the concept of a naming strategy. A naming strategy in NHibernate converts class and property names to table and column names and vice-versa, when a name is not explicitly supplied. In concrete, it must be a realization of the NHibernate.Cfg.INamingStrategy interface, of which NHibernate includes two implementations:

  • DefaultNamingStrategy: the default implementation, where each column and table are mapped to identically named properties and classes, for example, “MyEntity” will translate to “MyEntity”;
  • ImprovedNamingStrategy: underscores (_) are used to separate Pascal-cased fragments, for example, entity “MyEntity” will be mapped to a “my_entity” table.

The naming strategy can be defined at configuration level (the Configuration instance) by calling the SetNamingStrategy method:

   1: cfg.SetNamingStrategy(ImprovedNamingStrategy.Instance);

Both the DefaultNamingStrategy and the ImprovedNamingStrategy classes offer singleton instances in the form of Instance static fields. DefaultNamingStrategy is the one NHibernate uses, if you don’t specify one.

Domain Mapping

In mapping by code, we have the choice of relying on conventions to do the mapping automatically. This means a class will inspect our classes and decide how they will relate to the database objects. The class that handles conventions is NHibernate.Mapping.ByCode.ConventionModelMapper, a specialization of the base by code mapper, NHibernate.Mapping.ByCode.ModelMapper. The ModelMapper relies on an internal SimpleModelInspector to help it decide what and how to map, but the mapper lets you override its decisions.  You apply code conventions like this:

   1: //pick the types that you want to map
   2: IEnumerable<Type> types = Assembly.GetExecutingAssembly().GetExportedTypes();
   3:  
   4: //conventions based mapper
   5: ConventionModelMapper mapper = new ConventionModelMapper();
   6:  
   7: HbmMapping mapping = mapper.CompileMappingFor(types);
   8:  
   9: //the one and only configuration instance
  10: Configuration cfg = ...;
  11: cfg.AddMapping(mapping);

This is a very simple example, it lacks, at least, the id generation strategy, which you can add by adding an event handler like this:

   1: mapper.BeforeMapClass += (IModelInspector modelInspector, Type type, IClassAttributesMapper classCustomizer) =>
   2: {
   3:     classCustomizer.Id(x =>
   4:     {
   5:         //set the hilo generator
   6:         x.Generator(Generators.HighLow);
   7:     });
   8: };

The mapper will fire events like this whenever it needs to get information about what to do. And basically this is all it takes to automatically map your domain! It will correctly configure many-to-one and one-to-many relations, choosing bags or sets depending on your collections, will get the table and column names from the naming strategy we saw earlier and will apply the usual defaults to all properties, such as laziness and fetch mode.

However, there is at least one thing missing: many-to-many relations. The conventional mapper doesn’t know how to find and configure them, which is a pity, but, alas, not difficult to overcome. To start, for my projects, I have this rule: each entity exposes a public property of type ISet<T> where T is, of course, the type of the other endpoint entity. Extensible as it is, NHibernate lets me implement this very easily:

   1: mapper.IsOneToMany((MemberInfo member, Boolean isLikely) =>
   2: {
   3:     Type sourceType = member.DeclaringType;
   4:     Type destinationType = member.GetMemberFromDeclaringType().GetPropertyOrFieldType();
   5:  
   6:     //check if the property is of a generic collection type
   7:     if ((destinationType.IsGenericCollection() == true) && (destinationType.GetGenericArguments().Length == 1))
   8:     {
   9:         Type destinationEntityType = destinationType.GetGenericArguments().Single();
  10:  
  11:         //check if the type of the generic collection property is an entity
  12:         if (mapper.ModelInspector.IsEntity(destinationEntityType) == true)
  13:         {
  14:             //check if there is an equivalent property on the target type that is also a generic collection and points to this entity
  15:             PropertyInfo collectionInDestinationType = destinationEntityType.GetProperties().Where(x => (x.PropertyType.IsGenericCollection() == true) && (x.PropertyType.GetGenericArguments().Length == 1) && (x.PropertyType.GetGenericArguments().Single() == sourceType)).SingleOrDefault();
  16:  
  17:             if (collectionInDestinationType != null)
  18:             {
  19:                 return (false);
  20:             }
  21:         }
  22:     }
  23:  
  24:     return (true);
  25: });
  26:  
  27: mapper.IsManyToMany((MemberInfo member, Boolean isLikely) =>
  28: {
  29:     //a relation is many to many if it isn't one to many
  30:     Boolean isOneToMany = mapper.ModelInspector.IsOneToMany(member);
  31:     return (!isOneToMany);
  32: });
  33:  
  34: mapper.BeforeMapManyToMany += (IModelInspector modelInspector, PropertyPath member, IManyToManyMapper collectionRelationManyToManyCustomizer) =>
  35: {
  36:     Type destinationEntityType = member.LocalMember.GetPropertyOrFieldType().GetGenericArguments().First();
  37:     //set the mapping table column names from each source entity name plus the _Id sufix
  38:     collectionRelationManyToManyCustomizer.Column(destinationEntityType.Name + "_Id");
  39: };
  40:  
  41: mapper.BeforeMapSet += (IModelInspector modelInspector, PropertyPath member, ISetPropertiesMapper propertyCustomizer) =>
  42: {
  43:     if (modelInspector.IsManyToMany(member.LocalMember) == true)
  44:     {
  45:         propertyCustomizer.Key(x => x.Column(member.LocalMember.DeclaringType.Name + "_Id"));
  46:  
  47:         Type sourceType = member.LocalMember.DeclaringType;
  48:         Type destinationType = member.LocalMember.GetPropertyOrFieldType().GetGenericArguments().First();
  49:         IEnumerable<String> names = new Type[] { sourceType, destinationType }.Select(x => x.Name).OrderBy(x => x);
  50:  
  51:         //set inverse on the relation of the alphabetically first entity name
  52:         propertyCustomizer.Inverse(sourceType.Name == names.First());
  53:         //set mapping table name from the entity names in alphabetical order
  54:         propertyCustomizer.Table(String.Join("_", names));
  55:     }
  56: };

We have to understand how the conventions mapper thinks:

  • For each collection of entities found, it will ask the mapper if it is a one-to-many; in our case, if the collection is a generic one that has an entity as its generic parameter, and the generic parameter type has a similar collection, then it is not a one-to-many;
  • Next, the mapper will ask if the collection that it now knows is not a one-to-many is a many-to-many;
  • Before a set is mapped, if it corresponds to a many-to-many, we set its mapping table. Now, this is tricky: because we have no way to maintain state, we sort the names of the two endpoint entities and we combine them with a “_”; for the first alphabetical entity, we set its relation to inverse – remember, on a many-to-many relation, only one endpoint must be marked as inverse; finally, we set the column name as the name of the entity with an “_Id” suffix;
  • Before the many-to-many relation is processed, we set the column name as the name of the other endpoint entity with the “_Id” suffix, as we did for the set.

And that’s it. With these rules, NHibernate will now happily find and configure many-to-many relations, as well as all the others. You can wrap this in a new conventions mapper class, so that it is more easily reusable:

   1: public class ManyToManyConventionModelMapper : ConventionModelMapper
   2: {
   3:     public ManyToManyConventionModelMapper()
   4:     {
   5:         base.IsOneToMany((MemberInfo member, Boolean isLikely) =>
   6:         {
   7:             return (this.IsOneToMany(member, isLikely));
   8:         });
   9:  
  10:         base.IsManyToMany((MemberInfo member, Boolean isLikely) =>
  11:         {
  12:             return (this.IsManyToMany(member, isLikely));
  13:         });
  14:  
  15:         base.BeforeMapManyToMany += this.BeforeMapManyToMany;
  16:         base.BeforeMapSet += this.BeforeMapSet;
  17:     }
  18:  
  19:     protected virtual Boolean IsManyToMany(MemberInfo member, Boolean isLikely)
  20:     {
  21:         //a relation is many to many if it isn't one to many
  22:         Boolean isOneToMany = this.ModelInspector.IsOneToMany(member);
  23:         return (!isOneToMany);
  24:     }
  25:  
  26:     protected virtual Boolean IsOneToMany(MemberInfo member, Boolean isLikely)
  27:     {
  28:         Type sourceType = member.DeclaringType;
  29:         Type destinationType = member.GetMemberFromDeclaringType().GetPropertyOrFieldType();
  30:  
  31:         //check if the property is of a generic collection type
  32:         if ((destinationType.IsGenericCollection() == true) && (destinationType.GetGenericArguments().Length == 1))
  33:         {
  34:             Type destinationEntityType = destinationType.GetGenericArguments().Single();
  35:  
  36:             //check if the type of the generic collection property is an entity
  37:             if (this.ModelInspector.IsEntity(destinationEntityType) == true)
  38:             {
  39:                 //check if there is an equivalent property on the target type that is also a generic collection and points to this entity
  40:                 PropertyInfo collectionInDestinationType = destinationEntityType.GetProperties().Where(x => (x.PropertyType.IsGenericCollection() == true) && (x.PropertyType.GetGenericArguments().Length == 1) && (x.PropertyType.GetGenericArguments().Single() == sourceType)).SingleOrDefault();
  41:  
  42:                 if (collectionInDestinationType != null)
  43:                 {
  44:                     return (false);
  45:                 }
  46:             }
  47:         }
  48:  
  49:         return (true);
  50:     }
  51:  
  52:     protected virtual new void BeforeMapManyToMany(IModelInspector modelInspector, PropertyPath member, IManyToManyMapper collectionRelationManyToManyCustomizer)
  53:     {
  54:         Type destinationEntityType = member.LocalMember.GetPropertyOrFieldType().GetGenericArguments().First();
  55:         //set the mapping table column names from each source entity name plus the _Id sufix
  56:         collectionRelationManyToManyCustomizer.Column(destinationEntityType.Name + "_Id");
  57:     }
  58:  
  59:     protected virtual new void BeforeMapSet(IModelInspector modelInspector, PropertyPath member, ISetPropertiesMapper propertyCustomizer)
  60:     {
  61:         if (modelInspector.IsManyToMany(member.LocalMember) == true)
  62:         {
  63:             propertyCustomizer.Key(x => x.Column(member.LocalMember.DeclaringType.Name + "_Id"));
  64:  
  65:             Type sourceType = member.LocalMember.DeclaringType;
  66:             Type destinationType = member.LocalMember.GetPropertyOrFieldType().GetGenericArguments().First();
  67:             IEnumerable<String> names = new Type[] { sourceType, destinationType }.Select(x => x.Name).OrderBy(x => x);
  68:  
  69:             //set inverse on the relation of the alphabetically first entity name
  70:             propertyCustomizer.Inverse(sourceType.Name == names.First());
  71:             //set mapping table name from the entity names in alphabetical order
  72:             propertyCustomizer.Table(String.Join("_", names));
  73:         }
  74:     }
  75: }

Conclusion

Of course, there is much more to mapping than this, I suggest you look at all the events and functions offered by the ModelMapper to see where you can hook for making it behave the way you want. If you need any help, just let me know!

Dynamic LINQ Extension Method

Remember those old posts on Dynamic LINQ? You are probably aware that Microsoft has made its implementation available as a Nuget package, but, like I said, you already have it in your machine, hidden inside the System.Web.Extensions assembly.

In order to make it easier to use, I wrote a simple extension method that works with plain old IQueryable<T>. And here it is:

   1: public static IQueryable<T> Where<T>(this IQueryable<T> query, String restriction, params Object[] values)
   2: {
   3:     Assembly asm = typeof(UpdatePanel).Assembly;
   4:     Type dynamicExpressionType = asm.GetType("System.Web.Query.Dynamic.DynamicExpression");
   5:     MethodInfo parseLambdaMethod = dynamicExpressionType.GetMethods(BindingFlags.Public | BindingFlags.Static).Where(m => (m.Name == "ParseLambda") && (m.GetParameters().Length == 2)).Single().MakeGenericMethod(typeof(T), typeof(Boolean));
   6:     Expression<Func<T, Boolean>> expression = parseLambdaMethod.Invoke(null, new Object[] { restriction, values }) as Expression<Func<T, Boolean>>;
   7:  
   8:     return (query.Where(expression));
   9: }

It even supports parameters! Just two simple examples – I am using Entity Framework, but you can use whatever you like, this is totally generic:

   1: //without parameters
   2: var productsWithPriceGreaterThan100 = ctx.Products.Where("Price > 100").ToList();
   3:  
   4: //with parameters
   5: var productsWithPriceLowerThan100 = ctx.Products.Where("Price < @0", 100).ToList();

To make it clear, all parameters must be indicated as @0, @1, and so on. It is better to use them, because the database engine can reuse the execution plan.

There’s one limitation, though: you can’t compare each value on its own, you have to specify one of its properties. For example, you can’t have:

   1: var productNames = ctx.Products.Select(x => x.Name).Where("@it != @0", "Some Name").ToList();

The @it parameter is not recognized, which is a pity.

Make sure you have references to both System.Web and System.Web.Extensions, this is required, and won’t affect anything.

As always, glad to be of service! Winking smile

Posted: Jun 13 2013, 07:30 PM by Ricardo Peres | with 1 comment(s)
Filed under: ,
Comparing LINQ Expressions

Introduction

I recently came upon this problem: how to calculate a hash from a LINQ expression so that I can safely compare two expressions for equality? I had naively assumed that the Expression class – and their descendants – would have implemented GetHashCode in an appropriate way, so as to make developer’s lifes easier, but unfortunately Microsoft thought otherwise.

After looking it up on the Internet, I could see two “solutions”:

  • Convert the Expression to its string representation and get the hash code of it;
  • Use an ExpressionVisitor to visit all contained expressions and calculate their individual hash – if this seems recursive to you, that’s because it is!

Comparing the String Representation

The first “solution” doesn’t actually work, because two expressions might represent exactly the same and yet have different string representations. For example, consider:

   1: Expression<Func<Int32, Boolean>> isEven = x => (x % 2) == 0;

and

   1: Expression<Func<Int32, Boolean>> isEven = n => (n % 2) == 0;

The only thing that differentiates these two expressions is the name of the lambda parameter, unfortunately it causes their string representations to be different.

One possible solution might be to use a regular expression to get all occurrences of lambda expressions, capture the name of the lambda variables, and then do a search and replace for some well known name:

   1: var original = expression.ToString();
   2: var replaced = original;
   3: var reParameterDeclaration = new Regex(@"(?<it>\w+)\s=>\s");
   4: var matches = reParameterDeclaration.Matches(original);
   5:  
   6: for (var i = 0; i < matches.Count; ++i)
   7: {
   8:     var match = matches[i];
   9:     var it = match.Groups[1].Value;
  10:  
  11:     replaced = Regex.Replace(replaced, String.Format(@"\b{0}\b", it), "it");
  12: }
  13:  
  14: Int32 hashCode = replaced.GetHashCode();

At first sight – at least, for me! – this seemed to work, however, the replacement pattern – “get me all words composed of only the lambda variable” -  might match something that it wasn’t supposed to, for instance:

   1: //here it works
   2: Expression<Func<Int32, Boolean>> isEven = x => ((x % 2) == 0);
   3:  
   4: //here it doesn't, because the x inside the string is also matched
   5: Expression<Func<String, String>> x => "x y z";

I might use a different replacement regular expression, for example, I could check for “all lambda variables followed by a dot (.)”:

   1: replaced = Regex.Replace(replaced, String.Format(@"\b{0}\.", it), "it");

But this wouldn’t get code like this:

   1: //won't work because there's no dot after the lambda variable x
   2: var sortedNames = names.OrderBy(x => x);

To call it off, I think it might be possible, but it is more complicated than it seems.

Using an ExpressionVisitor

The next approach involves using an ExpressionVisitor to visit all expressions contained in an Expression, something that I have talked before. The thing here is, an Expression is typically composed of several other expressions, of various kinds, so appropriate code must be used for each in order to get an univocal hash out of it. For example, for a ConstantExpression, we might consider its NodeType, Type and Value properties. The problem is, there are more than 20 Expression subclasses, and we need to do this for each.

To cut things short, suppose we have implemented an hash code extractor for each Expression kind. We can’t simply have a big hash code by adding all hash codes calculated for each Expression fragment, because the order by which they appear is also important:

   1: //first take 10 elements and then sort them
   2: var pagedSortedNames = names.Take(10).OrderBy(x => x);
   3:  
   4: //first sort all elements then take 10 of them
   5: var sortedPagedNames = names.OrderBy(x => x).Take(10);

So, each individual hash code must be take in order, and then we must get the hash code of the entire list of hash codes. Uff!

Existing Implementations

This problem exists since there are LINQ expressions, and, of course, other folks have come up with solutions. The NHibernate project has one, probably LINQ to SQL and Entity Framework have too, just to name those more close to me. However, I don’t think any of these solutions might be ready for external, general purpose usage outside their source projects. It would be great to have one such library that we could pick up and use, but I haven’t so far found any. Might be something to work on, though.

What are your thoughts?

Posted: Jun 12 2013, 07:29 PM by Ricardo Peres | with 2 comment(s)
Filed under: ,
Entity Framework Metadata

Sometimes it is useful to know something about the physical storage of a code first model. Maybe it’s for SQL reporting or for any other matter, I sometimes have the need to look up the table name where an entity is stored or the column that holds some relation.

Entity Framework does not directly offer such information, but it is quite easy to get it. The key point here is the MetadataWorkspace property of the ObjectContext class. It exposes a cryptic GetItems method from which we can get to basically anywhere in the internal metadata configuration store. I have written wrappers to simplify using the configuration store, namely:

  • GetTables: return all of the mapped entities and their backend tables;
  • GetTableName: the name of the physical table where an entity is stored;
  • OneToMany/OneToOne/ManyToOne/ManyToMany: returns the collection of properties that support each of these relations for a specific entity type;
  • GetProperties: returns all of the scalar properties that are mapped for an entity type;
  • GetNavigationProperties: all of the navigation properties (one-to-one, one-to-many, many-to-one, many-to-many) exposed by an entity type;
  • GetIdProperties: the properties that store the id of an entity;
  • GetTableColumns: the mapped properties of an entity and their corresponding columns;
  • GetTableKeyColumns: the mapped properties that store the id of an entity and their corresponding columns;
  • GetTableNavigationColumns: the mapped properties that store the relations of an entity and their corresponding columns.

OK, so here is the code, as extension methods to DbContext:

   1: public static class DbContextExtensions
   2: {
   3:     public static IDictionary<Type, String> GetTables(this DbContext ctx)
   4:     {
   5:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
   6:         IEnumerable<EntityType> entities = octx.MetadataWorkspace.GetItemCollection(DataSpace.OSpace).GetItems<EntityType>().ToList();
   7:  
   8:         return(entities.ToDictionary(x => Type.GetType(x.FullName), x => GetTableName(ctx, Type.GetType(x.FullName))));
   9:     }
  10:  
  11:     public static String GetTableName(this DbContext ctx, Type entityType)
  12:     {
  13:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  14:         EntitySetBase et = octx.MetadataWorkspace.GetItemCollection(DataSpace.SSpace)
  15:             .GetItems<EntityContainer>()
  16:             .Single()
  17:             .BaseEntitySets
  18:             .Where(x => x.Name == entityType.Name)
  19:             .Single();
  20:  
  21:         String tableName = String.Concat(et.MetadataProperties["Schema"].Value, ".", et.MetadataProperties["Table"].Value);
  22:  
  23:         return (tableName);
  24:     }
  25:  
  26:     public static IEnumerable<PropertyInfo> OneToMany(this DbContext ctx, Type entityType)
  27:     {
  28:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  29:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  30:  
  31:         return (et.NavigationProperties.Where(x => x.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One && x.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many).Select(x => entityType.GetProperty(x.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)).ToList());
  32:     }
  33:  
  34:     public static IEnumerable<PropertyInfo> OneToOne(this DbContext ctx, Type entityType)
  35:     {
  36:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  37:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  38:  
  39:         return (et.NavigationProperties.Where(x => (x.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || x.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne) && (x.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One || x.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)).Select(x => entityType.GetProperty(x.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)).ToList());
  40:     }
  41:  
  42:     public static IEnumerable<PropertyInfo> ManyToOne(this DbContext ctx, Type entityType)
  43:     {
  44:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  45:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  46:  
  47:         return (et.NavigationProperties.Where(x => x.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many && x.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.One).Select(x => entityType.GetProperty(x.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)).ToList());
  48:     }
  49:  
  50:     public static IEnumerable<PropertyInfo> ManyToMany(this DbContext ctx, Type entityType)
  51:     {
  52:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  53:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  54:         
  55:         return(et.NavigationProperties.Where(x => x.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many && x.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many).Select(x => entityType.GetProperty(x.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty)).ToList());
  56:     }
  57:  
  58:     public static IEnumerable<PropertyInfo> GetIdProperties(this DbContext ctx, Type entityType)
  59:     {
  60:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  61:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  62:  
  63:         return (et.KeyMembers.Select(x => entityType.GetProperty(x.Name)).ToList());
  64:     }
  65:  
  66:     public static IEnumerable<PropertyInfo> GetNavigationProperties(this DbContext ctx, Type entityType)
  67:     {
  68:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  69:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  70:  
  71:         return (et.NavigationProperties.Select(x => entityType.GetProperty(x.Name)).ToList());
  72:     }
  73:  
  74:     public static IEnumerable<PropertyInfo> GetIdProperties(this DbContext ctx, Type entityType)
  75:     {
  76:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  77:         EntityType et = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  78:  
  79:         return (et.KeyMembers.Select(x => entityType.GetProperty(x.Name)).ToList());
  80:     }
  81:  
  82:     public static IDictionary<String, PropertyInfo> GetTableKeyColumns(this DbContext ctx, Type entityType)
  83:     {
  84:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  85:         EntityType storageEntityType = octx.MetadataWorkspace.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  86:         EntityType objectEntityType = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  87:         return (storageEntityType.KeyMembers.Select((elm, index) => new { elm.Name, Property = entityType.GetProperty((objectEntityType.MetadataProperties["Members"].Value as IEnumerable<EdmMember>).ElementAt(index).Name) }).ToDictionary(x => x.Name, x => x.Property));
  88:     }
  89:  
  90:     public static IDictionary<String, PropertyInfo> GetTableColumns(this DbContext ctx, Type entityType)
  91:     {
  92:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
  93:         EntityType storageEntityType = octx.MetadataWorkspace.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  94:         EntityType objectEntityType = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
  95:         return (storageEntityType.Properties.Select((elm, index) => new { elm.Name, Property = entityType.GetProperty(objectEntityType.Members[index].Name) }).ToDictionary(x => x.Name, x => x.Property));
  96:     }
  97:  
  98:     public static IDictionary<String, PropertyInfo> GetTableNavigationColumns(this DbContext ctx, Type entityType)
  99:     {
 100:         ObjectContext octx = (ctx as IObjectContextAdapter).ObjectContext;
 101:         EntityType storageEntityType = octx.MetadataWorkspace.GetItems(DataSpace.SSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
 102:         EntityType objectEntityType = octx.MetadataWorkspace.GetItems(DataSpace.OSpace).Where(x => x.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(x => x.Name == entityType.Name).Single();
 103:         return (storageEntityType.NavigationProperties.Select((elm, index) => new { elm.Name, Property = entityType.GetProperty(objectEntityType.Members[index].Name) }).ToDictionary(x => x.Name, x => x.Property));
 104:     }
 105: }

All of these methods have a generic version and a non-generic version; each take a Type for which to retrieve the metadata.

If you need some more information, feel free to ask me! Winking smile

Unity – Part 4: Extensions

Extensions

Another long overdue post on Unity. See the first here for an introduction, the second here for dependency injection and the third here for AOP with Unity.

Unity allows adding extensions to it. An extension is something that enhances its functionality somehow, or that configures some aspect of it so that you don’t have to do it manually. In Unity, an extension is a class that inherits from the abstract base class UnityContainerExtension. It can have multiple extensions, which are processed by the order on which they are declared – more on this later. The collection of actually loaded extensions is hidden inside of Unity, the only operations you can perform are add or remove an extension.

You already know from post three that if you want to use AOP – or Interception, in Unity terms – you must add the Interception extension. You also saw that we must tell Unity which of the interception strategies it must use for each registration upon which you want to apply aspects – VirtualMethodInterceptor, TransparentProxyInterceptor or InterfaceInterceptor. This is rather boring, so why not turn this into an extension that does all the work? The following code does just that:

   1: public class DefaultInterception : Interception
   2: {
   3:     #region Private static readonly fields
   4:     private static readonly IInterceptor [] interceptors = typeof(IInterceptor)
   5:         .Assembly
   6:         .GetExportedTypes()
   7:         .Where(type => 
   8:             (typeof(IInterceptor).IsAssignableFrom(type) == true) &&
   9:             (type.IsAbstract == false) &&
  10:             (type.IsInterface == false))
  11:         .Select(type => Activator.CreateInstance(type) as IInterceptor)
  12:         .ToArray();
  13:     #endregion
  14:  
  15:     #region Protected override methods
  16:     protected override void Initialize()
  17:     {
  18:         base.Initialize();
  19:  
  20:         IConfigurationSource configSource = ConfigurationSourceFactory.Create();
  21:         PolicyInjectionSettings section = configSource.GetSection(PolicyInjectionSettings.SectionName) as PolicyInjectionSettings;
  22:  
  23:         if (section != null)
  24:         {
  25:             section.ConfigureContainer(this.Container, configSource);
  26:         }
  27:  
  28:         this.Context.Registering += delegate(Object sender, RegisterEventArgs e)
  29:         {                
  30:             this.setInterceptorFor(e.TypeFrom, e.TypeTo, e.Name, e.LifetimeManager);
  31:         };
  32:  
  33:         this.Context.RegisteringInstance += delegate(Object sender, RegisterInstanceEventArgs e)
  34:         {
  35:             this.setInstanceInterceptorFor(e.RegisteredType, e.Name, e.Instance, e.LifetimeManager);
  36:         };
  37:     }
  38:     #endregion
  39:  
  40:     #region Private methods
  41:     private void setInterceptorFor(Type typeFrom, Type typeTo, String name, LifetimeManager lifetimeManager)
  42:     {
  43:         foreach (IInterceptor interceptor in interceptors)
  44:         {
  45:             if ((interceptor.CanIntercept(typeFrom) == true) && (interceptor.GetInterceptableMethods(typeFrom, typeTo).Count() != 0))
  46:             {
  47:                 if (interceptor is IInstanceInterceptor)
  48:                 {                        
  49:                     this.Container.Configure<Interception>().SetInterceptorFor(typeFrom, name, interceptor as IInstanceInterceptor);
  50:                 }
  51:                 else if (interceptor is ITypeInterceptor)
  52:                 {
  53:                     this.Container.Configure<Interception>().SetInterceptorFor(typeFrom, name, interceptor as ITypeInterceptor);
  54:                 }
  55:  
  56:                 //add a custom behavior for all types
  57:  
  58:                 break;
  59:             }
  60:         }
  61:     }
  62:  
  63:     private void setInstanceInterceptorFor(Type registeredType, String name, Object instance, LifetimeManager manager)
  64:     {
  65:         foreach (IInstanceInterceptor interceptor in interceptors.OfType<IInstanceInterceptor>())
  66:         {
  67:             if ((interceptor.CanIntercept(registeredType) == true) && (interceptor.GetInterceptableMethods(registeredType, instance.GetType()).Count() != 0))
  68:             {
  69:                 this.Container.Configure<Interception>().SetInterceptorFor(registeredType, name, interceptor);
  70:                 break;
  71:             }
  72:         }
  73:     }
  74:     #endregion
  75: }

As you can see, I inherited from Interception, which provides the AOP functionality, so I don't have to add it too. On the Initialize method we have access to both the Container (IUnityContainer) as well as a Context (ExtensionObject), which we can access freely. In this case, I hooked up to its Registering and RegisteringInstance events and, whenever a registration is made, I set up an appropriate interceptor, which I got from the list of default interceptor (IInterceptor) implementations.

Registration By Code

So, you need to register this extension, which you can do by code, by using the AddExtension or AddNewExtension<T> methods:

   1: IUnityContainer unity = ...;
   2:  
   3: unity.AddNewExtension<DefaultInterception>();

Beware, you must do this before actually registering something, because if you do it later, the events won’t get fired.

Registration By Configuration

If you place the registration on the .config file, you do no have to be concerned about doing it before the registrations:

   1: <configuration>
   2:     <configSections>
   3:         <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
   4:     </configSections>
   5:     <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
   6:         <container>
   7:             <extension type="MyNamespace.DefaultInterception, MyAssembly"/>
   8:         </container>
   9:     </unity>
  10: </configuration>

Configuring

In both cases, if the extension needs configuring, you can access it by using the Configure method:

   1: DefaultInterception extension = unity.Configure<DefaultInterception>();

This will only return the already registered extension, not create a new one.

Other Uses

Other common uses might include, for example, setting up the Common Service Locator, or setting up some interception behavior.

Next in line: injecting values into registrations. Stay tuned!

The State of Entity Framework and NHibernate

Some time ago, I compared NHibernate and Entity Framework. It was from a very technical point of view, and I think it is still up to date. Today, I want to talk about the current state of things, from a less technical stand.

First, let me just say the obvious: NHibernate originated and is driven by the community, while Entity Framework is a Microsoft product. This makes all the difference in the world.

Entity Framework has a roadmap, a plan and a permanent team focused on the product, while NHibernate has nothing like this. The NHibernate community consists of some very talented programmers who spend some of their free time working on NHibernate just for the fun of it. However, it is not their main occupation, and so many questions and community requests get unanswered, reported issues pile up, parts of the codebase are really not very good and there are several remarkable features missing – the NHibernate guys used to bash Entity Framework for not supporting enumerated types, but NHibernate, in 2013, still targets .NET 3.5, does not support left joins in LINQ queries, is scarcely documented and still requires the usage of an obscure collection library called Iesi.Collections. Of course, being a community thing, anyone can jump in and help with this, and in fact, there are lots of people contributing with pull requests, suggestions and bug reports. NHibernate’s problem, in my opinion, is lack of leadership. As far as I know, it is not known if the next version of NHibernate will be 3.4 or 4, and what will be there, except, of course, bug fixes, and even less what will NHibernate evolve to, when will it support .NET 4.5 constructs such as async, and so on. The NHibernate Development list is very quiet, and these questions, as well as lots of others, have had no response to this date.

While Entity Framework’s functionality is way behind NHibernate – and believe me, it really is – it is gaining ground. Entity Framework has a leader, a well known team which makes its discussions publicly available and takes suggestions from the community in the form of requests and even code patches, some of which have already been incorporated in the main product. The next major version, 6, was announced some time ago, public betas already exist – and, of course, anyone can get the current version from CodePlex – and it points to a direction. Granted, it is not going to address any of NHibernate’s stronger points, but instead it is moving with what appears to be the current trend, namely, asynchronicity, .NET 4.5 integration and conventions.

I don’t think NHibernate is dead yet, but some things really need to change to make it a modern competitor to other O/RMs, if there is interest in it. There are other things than just functionality.

Intercepting LINQ Queries

A common request when working with LINQ queries (Entity Framework, NHibernate, etc) is the ability to intercept them, that is, inspect an existing query and possibly modify something in it. This is not extremely difficult to do “by hand”, but Microsoft has a nice class called ExpressionVisitor which makes the job easier. It basically has virtual methods that get called whenever the class visits each expression contained in a greater expression, which may come from a query (the IQueryable interface exposes the underlying Expression in its Expression property). The virtual methods even allow returning a replacement for each expression found, the only problem is that you must subclass ExpressionVisitor to make even the slightest change, so I wrote my own class, which exposes all node traversal as events, one event for each kind of expression, where you can return an alternative expression, thus changing the original query. Here is the code for it:

   1: public sealed class ExpressionInterceptor : ExpressionVisitor
   2: {
   3:     #region Public events
   4:     public event Func<BinaryExpression, BinaryExpression> Binary;
   5:     public event Func<BlockExpression, BlockExpression> Block;
   6:     public event Func<CatchBlock, CatchBlock> CatchBlock;
   7:     public event Func<ConditionalExpression, ConditionalExpression> Conditional;
   8:     public event Func<ConstantExpression, ConstantExpression> Constant;
   9:     public event Func<DebugInfoExpression, DebugInfoExpression> DebugInfo;
  10:     public event Func<DefaultExpression, DefaultExpression> Default;
  11:     public event Func<DynamicExpression, DynamicExpression> Dynamic;
  12:     public event Func<ElementInit, ElementInit> ElementInit;
  13:     public event Func<Expression, Expression> Expression;
  14:     public event Func<Expression, Expression> Extension;
  15:     public event Func<GotoExpression, GotoExpression> Goto;
  16:     public event Func<IndexExpression, IndexExpression> Index;
  17:     public event Func<InvocationExpression, InvocationExpression> Invocation;
  18:     public event Func<LabelExpression, LabelExpression> Label;
  19:     public event Func<LabelTarget, LabelTarget> LabelTarget;
  20:     public event Func<LambdaExpression, LambdaExpression> Lambda;
  21:     public event Func<ListInitExpression, ListInitExpression> ListInit;
  22:     public event Func<LoopExpression, LoopExpression> Loop;
  23:     public event Func<MemberExpression, MemberExpression> Member;
  24:     public event Func<MemberAssignment, MemberAssignment> MemberAssignment;
  25:     public event Func<MethodCallExpression, MethodCallExpression> MethodCall;
  26:     public event Func<MemberInitExpression, MemberInitExpression> MemberInit;
  27:     public event Func<NewExpression, NewExpression> New;
  28:     public event Func<NewArrayExpression, NewArrayExpression> NewArray;
  29:     public event Func<ParameterExpression, ParameterExpression> Parameter;
  30:     public event Func<RuntimeVariablesExpression, RuntimeVariablesExpression> RuntimeVariables;
  31:     public event Func<SwitchExpression, SwitchExpression> Switch;
  32:     public event Func<TryExpression, TryExpression> Try;
  33:     public event Func<TypeBinaryExpression, TypeBinaryExpression> TypeBinary;
  34:     public event Func<UnaryExpression, UnaryExpression> Unary;
  35:     #endregion
  36:  
  37:     #region Public methods
  38:     public IQueryable<T> Visit<T>(IQueryable<T> query)
  39:     {
  40:         return (this.Visit(query as IQueryable) as IQueryable<T>);
  41:     }
  42:  
  43:     public IQueryable<T> Visit<T, TExpression>(IQueryable<T> query, Func<TExpression, TExpression> action) where TExpression : Expression
  44:     {
  45:         EventInfo evt = this.GetType().GetEvents(BindingFlags.Public | BindingFlags.Instance).Where(x => x.EventHandlerType == typeof(Func<TExpression, TExpression>)).First();
  46:         evt.AddEventHandler(this, action);
  47:  
  48:         query = this.Visit(query);
  49:  
  50:         evt.RemoveEventHandler(this, action);
  51:  
  52:         return (query);
  53:     }
  54:  
  55:     public IQueryable Visit(IQueryable query)
  56:     {
  57:         return (query.Provider.CreateQuery(this.Visit(query.Expression)));
  58:     }
  59:  
  60:     public IEnumerable<Expression> Flatten(IQueryable query)
  61:     {
  62:         Queue<Expression> list = new Queue<Expression>();
  63:         Func<Expression, Expression> action = delegate(Expression expression)
  64:         {
  65:             if (expression != null)
  66:             {
  67:                 list.Enqueue(expression);
  68:             }
  69:  
  70:             return (expression);
  71:         };
  72:  
  73:         this.Expression += action;
  74:  
  75:         this.Visit(query);
  76:  
  77:         this.Expression -= action;
  78:  
  79:         return (list);
  80:     }
  81:     #endregion
  82:  
  83:     #region Public override methods
  84:     public override Expression Visit(Expression node)
  85:     {
  86:         if ((this.Expression != null) && (node != null))
  87:         {
  88:             return(base.Visit(this.Expression(base.Visit(node))));
  89:         }
  90:         else
  91:         {
  92:             return (base.Visit(node));
  93:         }
  94:     }
  95:     #endregion
  96:  
  97:     #region Protected override methods
  98:     protected override Expression VisitNew(NewExpression node)
  99:     {
 100:         if ((this.New != null) && (node != null))
 101:         {
 102:             return (base.VisitNew(this.New(node)));
 103:         }
 104:         else
 105:         {
 106:             return (base.VisitNew(node));
 107:         }
 108:     }
 109:  
 110:     protected override Expression VisitNewArray(NewArrayExpression node)
 111:     {
 112:         if ((this.NewArray != null) && (node != null))
 113:         {
 114:             return (base.VisitNewArray(this.NewArray(node)));
 115:         }
 116:         else
 117:         {
 118:             return (base.VisitNewArray(node));
 119:         }
 120:     }
 121:  
 122:     protected override Expression VisitParameter(ParameterExpression node)
 123:     {
 124:         if ((this.Parameter != null) && (node != null))
 125:         {
 126:             return (base.VisitParameter(this.Parameter(node)));
 127:         }
 128:         else
 129:         {
 130:             return (base.VisitParameter(node));
 131:         }
 132:     }
 133:  
 134:     protected override Expression VisitRuntimeVariables(RuntimeVariablesExpression node)
 135:     {
 136:         if ((this.RuntimeVariables != null) && (node != null))
 137:         {
 138:             return (base.VisitRuntimeVariables(this.RuntimeVariables(node)));
 139:         }
 140:         else
 141:         {
 142:             return (base.VisitRuntimeVariables(node));
 143:         }
 144:     }
 145:  
 146:     protected override Expression VisitSwitch(SwitchExpression node)
 147:     {
 148:         if ((this.Switch != null) && (node != null))
 149:         {
 150:             return (base.VisitSwitch(this.Switch(node)));
 151:         }
 152:         else
 153:         {
 154:             return (base.VisitSwitch(node));
 155:         }
 156:     }
 157:  
 158:     protected override Expression VisitTry(TryExpression node)
 159:     {
 160:         if ((this.Try != null) && (node != null))
 161:         {
 162:             return (base.VisitTry(this.Try(node)));
 163:         }
 164:         else
 165:         {
 166:             return (base.VisitTry(node));
 167:         }
 168:     }
 169:  
 170:     protected override Expression VisitTypeBinary(TypeBinaryExpression node)
 171:     {
 172:         if ((this.TypeBinary != null) && (node != null))
 173:         {
 174:             return (base.VisitTypeBinary(this.TypeBinary(node)));
 175:         }
 176:         else
 177:         {
 178:             return (base.VisitTypeBinary(node));
 179:         }
 180:     }
 181:  
 182:     protected override Expression VisitUnary(UnaryExpression node)
 183:     {
 184:         if ((this.Unary != null) && (node != null))
 185:         {
 186:             return (base.VisitUnary(this.Unary(node)));
 187:         }
 188:         else
 189:         {
 190:             return (base.VisitUnary(node));
 191:         }
 192:     }
 193:  
 194:     protected override Expression VisitMemberInit(MemberInitExpression node)
 195:     {
 196:         if ((this.MemberInit != null) && (node != null))
 197:         {
 198:             return (base.VisitMemberInit(this.MemberInit(node)));
 199:         }
 200:         else
 201:         {
 202:             return (base.VisitMemberInit(node));
 203:         }
 204:     }
 205:  
 206:     protected override Expression VisitMethodCall(MethodCallExpression node)
 207:     {
 208:         if ((this.MethodCall != null) && (node != null))
 209:         {
 210:             return (base.VisitMethodCall(this.MethodCall(node)));
 211:         }
 212:         else
 213:         {
 214:             return (base.VisitMethodCall(node));
 215:         }
 216:     }
 217:  
 218:     
 219:     protected override Expression VisitLambda<T>(Expression<T> node)
 220:     {
 221:         if ((this.Lambda != null) && (node != null))
 222:         {
 223:             return (base.VisitLambda<T>(this.Lambda(node) as Expression<T>));
 224:         }
 225:         else
 226:         {
 227:             return (base.VisitLambda<T>(node));
 228:         }
 229:     }
 230:  
 231:     protected override Expression VisitBinary(BinaryExpression node)
 232:     {
 233:         if ((this.Binary != null) && (node != null))
 234:         {
 235:             return (base.VisitBinary(this.Binary(node)));
 236:         }
 237:         else
 238:         {
 239:             return (base.VisitBinary(node));
 240:         }
 241:     }
 242:  
 243:     protected override Expression VisitBlock(BlockExpression node)
 244:     {
 245:         if ((this.Block != null) && (node != null))
 246:         {
 247:             return (base.VisitBlock(this.Block(node)));
 248:         }
 249:         else
 250:         {
 251:             return (base.VisitBlock(node));
 252:         }
 253:     }
 254:  
 255:     protected override CatchBlock VisitCatchBlock(CatchBlock node)
 256:     {
 257:         if ((this.CatchBlock != null) && (node != null))
 258:         {
 259:             return (base.VisitCatchBlock(this.CatchBlock(node)));
 260:         }
 261:         else
 262:         {
 263:             return (base.VisitCatchBlock(node));
 264:         }
 265:     }
 266:  
 267:     protected override Expression VisitConditional(ConditionalExpression node)
 268:     {
 269:         if ((this.Conditional != null) && (node != null))
 270:         {
 271:             return (base.VisitConditional(this.Conditional(node)));
 272:         }
 273:         else
 274:         {
 275:             return (base.VisitConditional(node));
 276:         }
 277:     }
 278:  
 279:     protected override Expression VisitConstant(ConstantExpression node)
 280:     {
 281:         if ((this.Constant != null) && (node != null))
 282:         {
 283:             return (base.VisitConstant(this.Constant(node)));
 284:         }
 285:         else
 286:         {
 287:             return (base.VisitConstant(node));
 288:         }
 289:     }
 290:  
 291:     protected override Expression VisitDebugInfo(DebugInfoExpression node)
 292:     {
 293:         if ((this.DebugInfo != null) && (node != null))
 294:         {
 295:             return (base.VisitDebugInfo(this.DebugInfo(node)));
 296:         }
 297:         else
 298:         {
 299:             return (base.VisitDebugInfo(node));
 300:         }
 301:     }
 302:  
 303:     protected override Expression VisitDefault(DefaultExpression node)
 304:     {
 305:         if ((this.Default != null) && (node != null))
 306:         {
 307:             return (base.VisitDefault(this.Default(node)));
 308:         }
 309:         else
 310:         {
 311:             return (base.VisitDefault(node));
 312:         }
 313:     }
 314:  
 315:     protected override Expression VisitDynamic(DynamicExpression node)
 316:     {
 317:         if ((this.Dynamic != null) && (node != null))
 318:         {
 319:             return (base.VisitDynamic(this.Dynamic(node)));
 320:         }
 321:         else
 322:         {
 323:             return (base.VisitDynamic(node));
 324:         }
 325:     }
 326:  
 327:     protected override ElementInit VisitElementInit(ElementInit node)
 328:     {
 329:         if ((this.ElementInit != null) && (node != null))
 330:         {
 331:             return (base.VisitElementInit(this.ElementInit(node)));
 332:         }
 333:         else
 334:         {
 335:             return (base.VisitElementInit(node));
 336:         }
 337:     }
 338:  
 339:     protected override Expression VisitExtension(Expression node)
 340:     {
 341:         if ((this.Extension != null) && (node != null))
 342:         {
 343:             return (base.VisitExtension(this.Extension(node)));
 344:         }
 345:         else
 346:         {
 347:             return (base.VisitExtension(node));
 348:         }
 349:     }
 350:  
 351:     protected override Expression VisitGoto(GotoExpression node)
 352:     {
 353:         if ((this.Goto != null) && (node != null))
 354:         {
 355:             return (base.VisitGoto(this.Goto(node)));
 356:         }
 357:         else
 358:         {
 359:             return (base.VisitGoto(node));
 360:         }
 361:     }
 362:  
 363:     protected override Expression VisitIndex(IndexExpression node)
 364:     {
 365:         if ((this.Index != null) && (node != null))
 366:         {
 367:             return (base.VisitIndex(this.Index(node)));
 368:         }
 369:         else
 370:         {
 371:             return (base.VisitIndex(node));
 372:         }
 373:     }
 374:  
 375:     protected override Expression VisitInvocation(InvocationExpression node)
 376:     {
 377:         if ((this.Invocation != null) && (node != null))
 378:         {
 379:             return (base.VisitInvocation(this.Invocation(node)));
 380:         }
 381:         else
 382:         {
 383:             return (base.VisitInvocation(node));
 384:         }
 385:     }
 386:  
 387:     protected override Expression VisitLabel(LabelExpression node)
 388:     {
 389:         if ((this.Label != null) && (node != null))
 390:         {
 391:             return (base.VisitLabel(this.Label(node)));
 392:         }
 393:         else
 394:         {
 395:             return (base.VisitLabel(node));
 396:         }
 397:     }
 398:  
 399:     protected override LabelTarget VisitLabelTarget(LabelTarget node)
 400:     {
 401:         if ((this.LabelTarget != null) && (node != null))
 402:         {
 403:             return (base.VisitLabelTarget(this.LabelTarget(node)));
 404:         }
 405:         else
 406:         {
 407:             return (base.VisitLabelTarget(node));
 408:         }
 409:     }
 410:  
 411:     protected override Expression VisitListInit(ListInitExpression node)
 412:     {
 413:         if ((this.ListInit != null) && (node != null))
 414:         {
 415:             return (base.VisitListInit(this.ListInit(node)));
 416:         }
 417:         else
 418:         {
 419:             return (base.VisitListInit(node));
 420:         }
 421:     }
 422:  
 423:     protected override Expression VisitLoop(LoopExpression node)
 424:     {
 425:         if ((this.Loop != null) && (node != null))
 426:         {
 427:             return (base.VisitLoop(this.Loop(node)));
 428:         }
 429:         else
 430:         {
 431:             return (base.VisitLoop(node));
 432:         }
 433:     }
 434:  
 435:     protected override Expression VisitMember(MemberExpression node)
 436:     {
 437:         if ((this.Member != null) && (node != null))
 438:         {
 439:             return (base.VisitMember(this.Member(node)));
 440:         }
 441:         else
 442:         {
 443:             return (base.VisitMember(node));
 444:         }
 445:     }
 446:  
 447:     protected override MemberAssignment VisitMemberAssignment(MemberAssignment node)
 448:     {
 449:         if ((this.MemberAssignment != null) && (node != null))
 450:         {
 451:             return (base.VisitMemberAssignment(this.MemberAssignment(node)));
 452:         }
 453:         else
 454:         {
 455:             return (base.VisitMemberAssignment(node));
 456:         }
 457:     }
 458:     #endregion        
 459: }

Yes, I know, I probably should have used properties instead of events, but that’s really not important.

A simple example might be:

   1: ExpressionInterceptor interceptor = new ExpressionInterceptor();
   2: String[] lettersArray = new String[] { "A", "B", "C" };    //a data source
   3: IQueryable<String> lettersQuery = lettersArray.AsQueryable().Where(x => x == "A").OrderByDescending(x => x).Select(x => x.ToUpper());    //a silly query
   4: IQueryable<String> lettersInterceptedQuery = interceptor.Visit<String, MethodCallExpression>(lettersQuery, x =>
   5: {
   6:     if (x.Method.Name == "ToUpper")
   7:     {
   8:         //change from uppercase to lowercase
   9:         x = Expression.Call(x.Object, typeof(String).GetMethods().Where(y => y.Name == "ToLower").First());
  10:     }
  11:  
  12:     return (x);
  13: });
  14: lettersInterceptedQuery = interceptor.Visit<String, BinaryExpression>(lettersInterceptedQuery, x =>
  15: {
  16:     //change from qual to not equal
  17:     x = Expression.MakeBinary(ExpressionType.NotEqual, x.Left, x.Right);
  18:  
  19:     return (x);
  20: });
  21: IEnumerable<Expression> lettersExpressions = interceptor.Flatten(lettersQuery);    //all expressions found
  22: IEnumerable<String> lettersList = lettersQuery.ToList();    //"A"
  23: IEnumerable<String> lettersInterceptedList = lettersInterceptedQuery.ToList();    //"c", "b"

You see, I have methods that visit both an IQueryable, an IQueryable<T> or an Expression, and there is even an inline version that takes a Func<TExpression, TExpression> for even easier usage.

As always, hope you find it useful!

Posted: May 23 2013, 10:03 AM by Ricardo Peres | with no comments
Filed under: ,
Entity Framework Code First Fluent Validation

Back to Entity Framework Code First (EFCF) validation. On my previous post I mentioned that EFCF did not support fluent validation. While this is true, it isn’t too hard to implement one such mechanism, which is exactly why I am writing this! Smile

I will be using the SavingChanges event to inject the validation logic, which will be implemented by strongly typed delegates. Let’s see some code:

   1: public static class DbContextExtensions
   2: {
   3:     private static IDictionary<Type, Tuple<Delegate, String>> entityValidations = new ConcurrentDictionary<Type, Tuple<Delegate, String>>();
   4:  
   5:     public static void AddEntityValidation<TEntity>(this DbContext context, Func<TEntity, Boolean> validation, String message) where TEntity : class
   6:     {
   7:         if (context == null)
   8:         {
   9:             throw new ArgumentNullException("context");
  10:         }
  11:  
  12:         if (validation == null)
  13:         {
  14:             throw new ArgumentNullException("validation");
  15:         }
  16:  
  17:         if (String.IsNullOrWhiteSpace(message) == true)
  18:         {
  19:             throw new ArgumentNullException("message");
  20:         }
  21:  
  22:         if (entityValidations.ContainsKey(typeof(TEntity)) == false)
  23:         {
  24:             (context as IObjectContextAdapter).ObjectContext.SavingChanges += delegate
  25:             {
  26:                 if (context.Configuration.ValidateOnSaveEnabled == true)
  27:                 {
  28:                     IEnumerable<TEntity> entities = context.ChangeTracker.Entries<TEntity>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified).Select(x => x.Entity).ToList();
  29:  
  30:                     foreach (TEntity entity in entities)
  31:                     {
  32:                         String error = ValidateEntity(entity);
  33:  
  34:                         if (String.IsNullOrWhiteSpace(error) == false)
  35:                         {
  36:                             throw (new ValidationException(error));
  37:                         }
  38:                     }
  39:                 }
  40:             };
  41:         }
  42:  
  43:         entityValidations[typeof(TEntity)] = new Tuple<Delegate, String>(validation, message);
  44:     }
  45:  
  46:     private static String ValidateEntity<TEntity>(TEntity entity)
  47:     {
  48:         Type entityType = typeof(TEntity);
  49:  
  50:         if (entityValidations.ContainsKey(entityType) == true)
  51:         {
  52:             Tuple<Delegate, String> entry = entityValidations[entityType];
  53:             Func<TEntity, Boolean> validation = entry.Item1 as Func<TEntity, Boolean>;
  54:  
  55:             if (validation(entity) == false)
  56:             {
  57:                 return (entry.Item2);
  58:             }
  59:         }
  60:  
  61:         return (null);
  62:     }
  63: }

We have an extension method that allows declaring, for an entity type, a validation expression, such as this:

   1: ctx.AddEntityValidation<SomeEntity>(x => x.SomeProperty != null, "SomeProperty is required");

The validation will be fired when the SaveChanges method is called and the errors will be encapsulated in a ValidationException:

   1: try
   2: {
   3:     ctx.SaveChanges();
   4: }
   5: catch (ValidationException ex)
   6: {
   7:     //see content of ex.ValidationResult.ErrorMessage
   8: }

This code can certainly be improved – multiple validations per entity, property-based validations, etc – but I think it is good enough to illustrate my technique.

One final note: the fluent validation will only be fired if the ValidateOnSaveEnabled property is set to true, which is the default.

Entity Framework Code First Validation

Introduction

Most persistence frameworks implement some kind of custom validation of entities before they are sent to the database. By custom I mean something more than just “is not null”, “has XX characters”, etc. This typically includes individual properties as well as validation of the entity as a whole – for example, checking that a property’s value is valid when used together with another property’s value.

Entity Framework Code First is no exception. Out of the box it already offers a number of possibilities for validating entities that cover typical scenarios: validation by attributes or by a validation method. One validation left out is one based on XML, but since Code First doesn’t really use XML, it should be no surprise, and the other is fluent validation, something that really should be supported.

Let’s explore each of these possibilities.

Overriding ValidateEntity

The DbContext class has a virtual method called ShouldValidateEntity that is called for each entity about to be persisted – meaning, inserted or updated –, and, when it returns true – which it does by default – will trigger a call to ValidateEntity, another virtual method. In this method, we have a chance to validate our entities any way we like. An example might be, for instance, checking if the entity to be saved implements IDataErrorInfo and extract validation information from this implementation:

   1: protected override DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, IDictionary<Object, Object> items)
   2: {
   3:     DbEntityValidationResult result = base.ValidateEntity(entityEntry, items);
   4:     IDataErrorInfo dei = entityEntry.Entity as IDataErrorInfo;
   5:     
   6:     foreach (String propertyName in entityEntry.CurrentValues.PropertyNames)
   7:     {
   8:         String errorMessage = dei[propertyName];
   9:  
  10:         if (String.IsNullOrWhiteSpace(errorMessage) == false)
  11:         {
  12:             result.ValidationErrors.Add(new DbValidationError(propertyName, errorMessage));
  13:         }
  14:     }
  15:  
  16:     return (result);
  17: }

For the validation to occur, the ValidateOnSave property must be true, which it is by default.
Don’t forget to always call the base implementation!

Applying Validation Attributes

Another option, which also applies to ASP.NET MVC validation (see http://weblogs.asp.net/ricardoperes/archive/2012/06/03/asp-net-mvc-validation-complete.aspx) is using validation attributes, that is, attributes that inherit from ValidationAttribute. The base ValidateEntity method of DbContext also checks for these attributes, another reason why you should always call it. Let’s see an example:

   1: [Serializable]
   2: [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
   3: public sealed class PositiveAttribute : ValidationAttribute
   4: {
   5:     protected override ValidationResult IsValid(Object value, ValidationContext validationContext)
   6:     {
   7:         Int64 longValue = Convert.ToInt64(value);
   8:  
   9:         if (longValue <= 0)
  10:         {
  11:             return (new ValidationResult("Value cannot be negative or zero"));
  12:         }
  13:  
  14:         return (ValidationResult.Success);
  15:     }
  16: }

You would then apply this to some property in your entity:

   1: public class MyEntity
   2: {
   3:     [Positive]
   4:     public Int64 MyAlwaysPositiveNumber { get; set; }
   5: }

The “problem” with this approach is that you must include any assemblies containing these custom validation attributes together with your model. If they are on the same assembly, there’s no problem.

By the way, you can specify multiple validation attributes and you can even apply them to the whole class, not just a property.

Implementing IValidatableObject

Another option, also common to MVC, is having your entities implement IValidatableObject. This interface defines a contract for returning a collection of validation errors for an entity. Here’s a sample implementation:

   1: public class Contract : IValidatableObject
   2: {
   3:     public String Name { get; set; }
   4:     public DateTime StartDate { get; set; }
   5:     public DateTime EndDate { get; set; }
   6:  
   7:     public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
   8:     {
   9:         if (this.StartDate >= this.EndDate)
  10:         {
  11:             yield return (new ValidationResult("The end date is before or the same as the start date", new String[] { "StartDate", "EndDate" }));
  12:         }
  13:     }
  14: }

Handling SavingChanges Event

The “underlying” ObjectContext – which, in fact, is only created if requested – exposes a SavingChanges event which is triggered whenever Entity Framework is about to send changes to the database, typically whenever the SaveChanges method is called. If we handle this event, we can perform our custom validation before our entities are saved, and in case something is wrong we can throw an exception to cancel the saving process:

   1: (ctx as IObjectContextAdapter).ObjectContext.SavingChanges += ObjectContext_SavingChanges;
   2:  
   3: void ObjectContext_SavingChanges(Object sender, EventArgs e)
   4: {
   5:     ObjectContext octx = sender as ObjectContext;
   6:     IEnumerable<Object> entities = octx.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified).Select(x => x.Entity);
   7:  
   8:     //do custom validation and throw an exception if something wrong is found
   9:  
  10: }

This has the arguable advantage that it decouples the validation process from the entities and the context themselves.

Conclusion

In case you are using any of these validation techniques, always surround calls to SaveChanges inside a try…catch block and look out for a DbEntityValidationException or your own exception, if you followed the SavingChanges approach. Inside DbEntityValidationException you have an EntityValidationErrors that contains all the details:

   1: try
   2: {
   3:     ctx.SaveChanges();
   4: }
   5: catch (DbEntityValidationException ex)
   6: {
   7:     foreach (DbEntityValidationResult result in ex.EntityValidationErrors)
   8:     {
   9:         //..
  10:     }
  11: }

Alternatively, you can explicitly call GetValidationErrors and see the collection of errors from all sources, except, of course, SavingChanges, because the context is not actually in the process of saving changes, for all entities currently being tracked by the context.

The order by which these validation processes are applied is:

  1. ValidateEntity
  2. ValidationAttribute (from base ValidateEntity)
  3. IValidatableObject (from base ValidateEntity
  4. SavingChanges (only if no errors are found)

Pick the one that better suits your needs!

Blogs Portugueses Sobre SharePoint

This post is in portuguese only, sorry!

A partir de um comentário no LinkedIn, no grupo da Comunidade Portuguesa de SharePoint (http://www.linkedin.com/groups?home=&gid=996587&trk=anet_ug_hm) foi começada uma lista dos blogs de autores portugueses e brasileiros sobre SharePoint, ainda que não exclusivamente. Vou publicar essa lista aqui, e tentarei mantê-la actualizada.

Se conhecerem mais, por favor, comuniquem-mos!

More Posts Next page »