Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

May 2013 - Posts

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!

Actualizado a 14 de Agosto

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!

Using the Enterprise Library 6 Configuration Console with Visual Studio 2012

You will have to download and run the Configuration Console from http://www.microsoft.com/en-us/download/details.aspx?id=38789, there is no NuGet package for it. After that, you will get a context menu for each project on the solution for editing the configuration:

image

Filter Collections Automatically With Entity Framework Code First

Introduction

In some O/RMs, it is possible to specify automatic filters for entity collections such as one-to-many or many-to-many. These are applied automatically whenever these collections are being populated. Entity Framework does not offer one such mechanism, however, it is possible to implement it.

Context Collections

In Entity Framework Code First, entities are exposed as IDbSet<T> or DbSet<T> collections on a context, a DbContext-derived class. There is no way to automatically set a filter that will apply to all queries coming from these collections, unless we create our own IDbSet<T> class. Let’s call it FilteredDbSet<T> and have it implement the same interfaces as DbSet<T> so that it can be used instead of it transparently:

   1: public class FilteredDbSet<TEntity> : IDbSet<TEntity>, IOrderedQueryable<TEntity> where TEntity : class
   2: {
   3:     #region Private readonly fields
   4:     private readonly DbSet<TEntity> set;
   5:     private readonly Func<TEntity, Boolean> matchesFilter;
   6:     #endregion
   7:  
   8:     #region Public constructors
   9:     public FilteredDbSet(DbContext context, Expression<Func<TEntity, Boolean>> filter)
  10:     {
  11:         this.set = set;
  12:         this.Filter = filter;
  13:         this.matchesFilter = filter.Compile();
  14:     }
  15:  
  16:     #endregion
  17:  
  18:     #region Public properties
  19:     public Expression<Func<TEntity, Boolean>> Filter
  20:     {
  21:         get;
  22:         protected set;
  23:     }
  24:  
  25:     public IQueryable<TEntity> Unfiltered
  26:     {
  27:         get
  28:         {
  29:             return (this.set);
  30:         }
  31:     }
  32:     #endregion
  33:  
  34:     #region Public methods
  35:     public IQueryable<TEntity> Include(String path)
  36:     {
  37:         return (this.set.Include(path).Where(this.Filter));
  38:     }
  39:  
  40:     public DbSqlQuery<TEntity> SqlQuery(String sql, params Object[] parameters)
  41:     {
  42:         return (this.set.SqlQuery(sql, parameters));
  43:     }
  44:     #endregion
  45:  
  46:     #region IDbSet<TEntity> Members
  47:     TEntity IDbSet<TEntity>.Add(TEntity entity)
  48:     {
  49:         this.ThrowIfEntityDoesNotMatchFilter(entity);
  50:         return (this.set.Add(entity));
  51:     }
  52:  
  53:     TEntity IDbSet<TEntity>.Attach(TEntity entity)
  54:     {
  55:         this.ThrowIfEntityDoesNotMatchFilter(entity);
  56:         return (this.set.Attach(entity));
  57:     }
  58:  
  59:     TDerivedEntity IDbSet<TEntity>.Create<TDerivedEntity>()
  60:     {
  61:         var entity = this.set.Create<TDerivedEntity>();
  62:         return (entity as TDerivedEntity);
  63:     }
  64:  
  65:     TEntity IDbSet<TEntity>.Create()
  66:     {
  67:         var entity = this.set.Create();
  68:         return (entity);
  69:     }
  70:  
  71:     TEntity IDbSet<TEntity>.Find(params Object[] keyValues)
  72:     {
  73:         var entity = this.set.Find(keyValues);
  74:         ThrowIfEntityDoesNotMatchFilter(entity);
  75:         return (entity);
  76:     }
  77:  
  78:     TEntity IDbSet<TEntity>.Remove(TEntity entity)
  79:     {
  80:         ThrowIfEntityDoesNotMatchFilter(entity);
  81:         return (this.set.Remove(entity));
  82:     }
  83:  
  84:     ObservableCollection<TEntity> IDbSet<TEntity>.Local
  85:     {
  86:         get { return (this.set.Local); }
  87:     }
  88:     #endregion
  89:  
  90:     #region IEnumerable<TEntity> Members
  91:     IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
  92:     {
  93:         return (this.set.Where(this.Filter).GetEnumerator());
  94:     }
  95:     #endregion
  96:  
  97:     #region IEnumerable Members
  98:     IEnumerator IEnumerable.GetEnumerator()
  99:     {
 100:         return ((this as IEnumerable<TEntity>).GetEnumerator());
 101:     }
 102:     #endregion
 103:  
 104:     #region IQueryable Members
 105:     Type IQueryable.ElementType
 106:     {
 107:         get { return ((this.set as IQueryable).ElementType); }
 108:     }
 109:  
 110:     Expression IQueryable.Expression
 111:     {
 112:         get
 113:         {
 114:             return (this.set.Where(this.Filter).Expression);
 115:         }
 116:     }
 117:  
 118:     IQueryProvider IQueryable.Provider
 119:     {
 120:         get
 121:         {
 122:             return ((this.set as IQueryable).Provider);
 123:         }
 124:     }
 125:     #endregion
 126:  
 127:     #region Private methods
 128:     private void ThrowIfEntityDoesNotMatchFilter(TEntity entity)
 129:     {
 130:         if ((entity != null) && (this.matchesFilter(entity) == false))
 131:         {
 132:             throw (new ArgumentException("Entity does not match filter", "entity"));
 133:         }
 134:     }
 135:  
 136:     #endregion
 137: }

In the constructor of our DbContext, we create instances of this class, and pass a LINQ restriction query on its constructor:

   1: public MyContext : DbContext
   2: {
   3:     public MyContext()
   4:     {
   5:         this.Bases = new FilteredDbSet<Base>(this, x => x.SomeProperty == 1);
   6:     }
   7:  
   8:     public IDbSet<Base> Bases { get; protected set; }
   9: }

From now on, all queries over the Bases collection will be restricted.

Entity Collections

A different matter is collections on entities. For these, we usually declare a property of ICollection<T> and let Entity Framework create an instance for us, when it is loading the entity. The class responsible for creating this instance is DbCollectionEntry, which unfortunately does not allow subclassing, because it doesn’t have any public or protected constructors or virtual methods. Let’s take a different path and create our own collection class instead:

   1: [Serializable]
   2: public class FilteredCollection<T> : ICollection<T>
   3: {
   4:     private readonly DbCollectionEntry collectionEntry;
   5:     private readonly Func<T, Boolean> compiledFilter;
   6:     private ICollection<T> collection;
   7:  
   8:     public FilteredCollection(ICollection<T> collection, DbCollectionEntry collectionEntry, Expression<Func<T, Boolean>> filter)
   9:     {
  10:         this.Filter = filter;
  11:         this.collection = collection ?? new HashSet<T>();
  12:         this.collectionEntry = collectionEntry;
  13:         this.compiledFilter = filter.Compile();
  14:  
  15:         if (collection != null)
  16:         {
  17:             foreach (T entity in collection)
  18:             {
  19:                 this.collection.Add(entity);
  20:             }
  21:  
  22:             this.collectionEntry.CurrentValue = this;
  23:         }
  24:         else
  25:         {
  26:             this.LoadIfNecessary();
  27:         }
  28:     }
  29:  
  30:     public Expression<Func<T, Boolean>> Filter
  31:     {
  32:         get;
  33:         private set;
  34:     }
  35:  
  36:     protected void ThrowIfInvalid(T entity)
  37:     {
  38:         if (this.compiledFilter(entity) == false)
  39:         {
  40:             throw (new ArgumentException("entity"));
  41:         }
  42:     }
  43:  
  44:     protected void LoadIfNecessary()
  45:     {
  46:         if (this.collectionEntry.IsLoaded == false)
  47:         {
  48:             IQueryable<T> query = this.collectionEntry.Query().Cast<T>().Where(this.Filter);
  49:  
  50:             this.collection = query.ToList();
  51:  
  52:             this.collectionEntry.CurrentValue = this;
  53:  
  54:             var _internalCollectionEntry = this.collectionEntry.GetType().GetField("_internalCollectionEntry", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this.collectionEntry);
  55:             var _relatedEnd = _internalCollectionEntry.GetType().BaseType.GetField("_relatedEnd", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_internalCollectionEntry);
  56:             _relatedEnd.GetType().GetField("_isLoaded", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(_relatedEnd, true);
  57:         }
  58:     }
  59:  
  60:     #region ICollection<T> Members
  61:  
  62:     void ICollection<T>.Add(T item)
  63:     {
  64:         this.LoadIfNecessary();
  65:         this.ThrowIfInvalid(item);
  66:         this.collection.Add(item);
  67:     }
  68:  
  69:     void ICollection<T>.Clear()
  70:     {
  71:         this.LoadIfNecessary();
  72:         this.collection.Clear();
  73:     }
  74:  
  75:     Boolean ICollection<T>.Contains(T item)
  76:     {
  77:         this.LoadIfNecessary();
  78:         return (this.collection.Contains(item));
  79:     }
  80:  
  81:     void ICollection<T>.CopyTo(T[] array, Int32 arrayIndex)
  82:     {
  83:         this.LoadIfNecessary();
  84:         this.collection.CopyTo(array, arrayIndex);
  85:     }
  86:  
  87:     Int32 ICollection<T>.Count
  88:     {
  89:         get
  90:         {
  91:             this.LoadIfNecessary();
  92:             return (this.collection.Count);
  93:         }
  94:     }
  95:  
  96:     Boolean ICollection<T>.IsReadOnly
  97:     {
  98:         get
  99:         {
 100:             this.LoadIfNecessary();
 101:             return (this.collection.IsReadOnly);
 102:         }
 103:     }
 104:  
 105:     Boolean ICollection<T>.Remove(T item)
 106:     {
 107:         this.LoadIfNecessary();
 108:         return (this.collection.Remove(item));
 109:     }
 110:  
 111:     #endregion
 112:  
 113:     #region IEnumerable<T> Members
 114:  
 115:     IEnumerator<T> IEnumerable<T>.GetEnumerator()
 116:     {
 117:         this.LoadIfNecessary();
 118:         return (this.collection.GetEnumerator());
 119:     }
 120:  
 121:     #endregion
 122:  
 123:     #region IEnumerable Members
 124:  
 125:     IEnumerator IEnumerable.GetEnumerator()
 126:     {
 127:         return ((this as IEnumerable<T>).GetEnumerator());
 128:     }
 129:  
 130:     #endregion
 131: }

This collection receives a pointer to a possibly existing collection and a DbCollectionEntry responsible for loading this collection. We must use a bit of reflection magic to let DbCollectionEntry think that the collection was already loaded (IsLoaded), and instead load it ourselves, by applying our custom restriction to the expression returned by its Query method.

Now, in order to use this collection, we must intercept the ObjectMaterialized event of the underlying ObjectContext. We set up the filter through an extension method over DbContext:

   1: public static class DbContextExtensions
   2: {
   3:      public static void Filter<TContext, TParentEntity, TCollectionEntity>(this TContext context, Expression<Func<TContext, IDbSet<TParentEntity>>> path, Expression<Func<TParentEntity, ICollection<TCollectionEntity>>> collection, Expression<Func<TCollectionEntity, Boolean>> filter)
   4:         where TContext : DbContext
   5:         where TParentEntity : class, new()
   6:         where TCollectionEntity : class
   7:     {
   8:          (context as IObjectContextAdapter).ObjectContext.ObjectMaterialized += delegate(Object sender, ObjectMaterializedEventArgs e)
   9:         {
  10:             if (e.Entity is TParentEntity)
  11:             {
  12:                 String navigationProperty = collection.ToString().Split('.')[1];
  13:                 DbCollectionEntry col = context.Entry(e.Entity).Collection(navigationProperty);
  14:                 col.CurrentValue = new FilteredCollection<TCollectionEntity>(null, col, filter);
  15:             }
  16:         };
  17:     }
  18: }

The actual ICollection<T> is returned by setting a value to the DbCollectionEntry.CurrentValue property, and we set it to our collection

We use this extension method like this:

   1: ctx.Filter(p => p.Products, p => p.Details, p => p.SomeProperty == 0);

This will pick the Product entity from the Products context collection and filter its Details collection.

Conclusion

As you can see, even though Entity Framework does not have all functionality that we might be used to, it still offers enough extensibility points that allow us to built it ourselves. The same technique that I presented here can be used for building lazy loaded or even IQueryable<T> collections, both interesting ideas that I leave as an exercise to you!Winking smile

More Posts