Thursday, December 11, 2014

Entity-ORM Hybrid

Sometimes you end up working on a project that shifts away from Entity Framework in favor of something else, ADO.NET, Linq to Sql, an available ORM, or maybe even a homegrown ORM.  That's what happened at one client I've worked with.  There were a few reasons to move away from EF, mostly based on misunderstandings, database design, and lack of knowledge of the product.  But there are still some things EF does better than some other methods.  Instead of writing a new stored procedure in SQL Server every time we need to update one field, we set out to use the features of EF to make that happen a little more easily.  After all, isn't it better when you can pass two variables to your repository and just wait for the true/false response?  That's right, it is better.

Here's the code:

   1:  public bool Save<T>(T domainModel, string idFieldName) where T : class
   2:          {
   3:              var type = typeof(T);
   4:              var idProperty = type.GetProperty(idFieldName);
   5:              var domainModelIdValue = (int)idProperty.GetValue(domainModel, null);
   6:   
   7:              var match =
   8:                  Context.Set<T>().Where(PropertyEquals<T, int>(idProperty, domainModelIdValue)).ToList();
   9:   
  10:              // if there's more than one record with a matching ID field (which shouldn't be possible as long as our field is specified correctly) we can't do this update
  11:              // also, if there's no match from the database on the ID field, we can't do this update
  12:              if (!match.Any() || match.Count() > 1)
  13:              {
  14:                  return false;
  15:              }
  16:   
  17:              var firstMatch = match.First();
  18:   
  19:              // set all properties from the domain model passed to the match found in the database
  20:              Context.Entry(firstMatch).CurrentValues.SetValues(domainModel);
  21:   
  22:              var numberOfObjectsWrittenToUnderlyingDatabase = Context.SaveChanges();
  23:   
  24:              return numberOfObjectsWrittenToUnderlyingDatabase == 1;
  25:          }
  26:   
  27:          public Expression<Func<TItem, bool>> PropertyEquals<TItem, TValue>(PropertyInfo property, TValue value)
  28:          {
  29:              var param = Expression.Parameter(typeof(TItem));
  30:              var expressionProperty = Expression.Property(param, property);
  31:   
  32:              BinaryExpression body;
  33:              if (Nullable.GetUnderlyingType(expressionProperty.Type) != null)
  34:              {
  35:                  var comparisonValue = Expression.Convert(Expression.Constant(value), typeof(int?));
  36:                  body = Expression.Equal(expressionProperty, comparisonValue);
  37:              }
  38:              else
  39:              {
  40:                  body = Expression.Equal(Expression.Property(param, property), Expression.Constant(value));
  41:              }
  42:   
  43:              return Expression.Lambda<Func<TItem, bool>>(body, param);
  44:          }

No comments:

Post a Comment