Implementing Missing Features in Entity Framework Core – Part 3

Back after a few weeks. For those who don’t know, this series of posts is dedicated to bringing some of the futures that existed in Entity Framework but were dropped in Core. You can find the first post here and the second here.

This time, an often forgotten feature that didn’t made it to Core: entity validation. Most of the posts that talk about what’s new usually forget about validation having been left out.

In a nutshell, Entity Framework used to validate entities according to the System.ComponentModel.DataAnnotations API:

It’s simple to get these back, though. All you need to do is override SaveChanges and plug in the validation code for all new and modified entries:

public class MyContext : DbContext

{

    public override int SaveChanges(bool acceptAllChangesOnSuccess)

    {

        var serviceProvider = this.GetService<IServiceProvider>();

        var items = new Dictionary<object, object>();

        

        foreach (var entry in this.ChangeTracker.Entries().Where(e => (e.State == EntityState.Added) || (e.State == EntityState.Modified))

        {

            var entity = entry.Entity;

            var context = new ValidationContext(entity, serviceProvider, items);

            var results = new List<ValidationResult>();

 

            if (Validator.TryValidateObject(entity, context, results, true) == false)

            {

                foreach (var result in results)

                {

                    if (result != ValidationResult.Success)

                    {

                        throw new ValidationException(result.ErrorMessage);

                    }

                }

            }

        }

 

        return base.SaveChanges(acceptAllChangesOnSuccess);

    }

}

The key here is the Validator class: it knows how to perform all these validations, including finding all validation attributes in the class and in each property. In case of an error, we just throw a ValidationException with the error message, and the saving is aborted.

Entity Framework Pitfalls: Entity Refresh

After an entity is loaded by Entity Framework, it gets stored in its first level cache. After that, whenever EF executes a query that returns this entity, identified by its primary key, EF always returns the cached entry, and makes no attempt to see if the cached data (the rest of the properties) is still up to date with that returned from the query. This feature is common to other ORMs, but it may result in unexpected behavior – we cannot rely on the state of a loaded entity if the database can change by other processes..

The solution for EF pre-Core is either:

  • Remove (evict) the entity from first level cache, by marking it as detached, when we want it to be reloaded from the database:
MyEntity e = ...;

 

ctx.Entry(e).State = EntityState.Detached;

  • Explicitly ask for it to be reloaded:
MyEntity e = ...;

 

ctx.Entry(e).Reload();

In EF Core, there is no Reload method – although I did write an implementation for it –, so the only option is to detach the entity from the context.

Implementing Missing Features in Entity Framework Core – Part 2

This is the second in a series of posts about missing functionality in EF Core. You can find the first here.

Entity Framework used to support three ways to load related entities (one to one, one to many, many to one, many to many):

Entity Framework Core doesn’t include (yet) the explicit loading and lazy loading mechanisms. Lazy loading is not included because EF Core does not generate proxies for the entities it loads, and I guess nobody bothered to implement explicit loading. Well, that’s exactly what we’ll do here!

The idea is, even if we didn’t require a collection to be loaded when we issued the query, we can still load it afterwards. We should keep a syntax similar to the previous version, when this feature was available:

//load a blog

var blog = ctx.Blogs.Single(b => b.BlogId == 1);

 

//Posts collection is empty

blog.Posts.Count(); //0

 

//eager load all Posts

ctx.Entry(blog).Load(b => b.Posts);

 

//Posts collection is no longer empty

blog.Posts.Count(); //!= 0

 

We will create an extension method over EntityEntry<T>:

public static void Load<TSource, TDestination>(this EntityEntry<TSource> entry, Expression<Func<TSource, IEnumerable<TDestination>>> path, Expression<Func<TDestination, TSource>> pathBack = null) where TSource : class where TDestination : class

{

    var entity = entry.Entity;

    var context = entry.Context;

    var entityType = context.Model.FindEntityType(typeof(TSource));

    var keys = entityType.GetKeys();

    var keyValues = context.GetEntityKey(entity);

    var query = context.Set<TDestination>() as IQueryable<TDestination>;

    var parameter = Expression.Parameter(typeof(TDestination), "x");

    PropertyInfo foreignKeyProperty = null;

 

    if (pathBack == null)

    {

        foreignKeyProperty = typeof(TDestination).GetProperties().Single(p => p.PropertyType == typeof(TSource));

    }

    else

    {

        foreignKeyProperty = (pathBack.Body as MemberExpression).Member as PropertyInfo;

    }

 

    var i = 0;

 

    foreach (var property in keys.SelectMany(x => x.Properties))

    {

        var keyValue = keyValues[i];

 

        var expression = Expression.Lambda(

                Expression.Equal(

                    Expression.Property(Expression.Property(parameter, foreignKeyProperty.Name), property.Name),

                    Expression.Constant(keyValue)),

                parameter) as Expression<Func<TDestination, bool>>;

 

        query = query.Where(expression);

 

        i++;

    }

 

    var list = query.ToList();

 

    var prop = (path.Body as MemberExpression).Member as PropertyInfo;

    prop.SetValue(entity, list);

}

The GetEntityKey method was introduced in the previous post, but I will add it here, for your convenience:

public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class

{

    var state = context.Entry(entity);

    var metadata = state.Metadata;

    var key = metadata.FindPrimaryKey();

    var props = key.Properties.ToArray();

 

    return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();

}

You can see that the Load method takes two parameters: the first is required, it represents the collection that we with to load, the second is optional, and it represents the go-back property, in case there is more than one property of the root entity’s type. For example:

ctx.Entry(blog).Load(b => b.Posts, p => p.Blog);

In this case, the path p => p.Blog is needless, because a Post only belongs to one Blog.

A similar approach can be used to load explicitly other kinds of relations (one to one and many to one).

Hope you find this useful! Winking smile

Implementing Missing Features in Entity Framework Core

Introduction

By now, we all know that Entity Framework Core 1.0 will not include several features that we were used to. In this post, I will try to explain how we can get over this by implementing them ourselves, or, at least, working out some workaround.

This time, I am going to talk about mimicking the Reload and Find methods, plus, give a set of other useful methods for doing dynamic programming.

Find

Find lets us query an entity by its identifier. We will first define a strongly typed version:

public static TEntity Find<TEntity>(this DbSet<TEntity> set, params object[] keyValues) where TEntity : class

{

    var context = set.GetInfrastructure<IServiceProvider>().GetService<DbContext>();

    var entityType = context.Model.FindEntityType(typeof(TEntity));

    var keys = entityType.GetKeys();

    var entries = context.ChangeTracker.Entries<TEntity>();

    var parameter = Expression.Parameter(typeof(TEntity), "x");

    IQueryable<TEntity> query = context.Set<TEntity>();

 

    //first, check if the entity exists in the cache

    var i = 0;

 

    //iterate through the key properties

    foreach (var property in keys.SelectMany(x => x.Properties))

    {

        var keyValue = keyValues[i];

 

        //try to get the entity from the local cache

        entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

 

        //build a LINQ expression for loading the entity from the store

        var expression = Expression.Lambda(

                Expression.Equal(

                    Expression.Property(parameter, property.Name),

                    Expression.Constant(keyValue)),

                parameter) as Expression<Func<TEntity, bool>>;

 

        query = query.Where(expression);

 

        i++;

    }

 

    var entity = entries.Select(x => x.Entity).FirstOrDefault();

 

    if (entity != null)

    {

        return entity;

    }

 

    //second, try to load the entity from the data store

    entity = query.FirstOrDefault();

 

    return entity;

}

And then a loosely-typed one:

private static readonly MethodInfo SetMethod = typeof(DbContext).GetTypeInfo().GetDeclaredMethod("Set");

 

public static object Find(this DbContext context, Type entityType, params object[] keyValues)

{

    dynamic set = SetMethod.MakeGenericMethod(entityType).Invoke(context, null);

    var entity = Find(set, keyValues);

    return entity;

}

Not sure if you’ve had to do queries through an entity’s Type, but I certainly have!

The Find method will first look in the DbContext local cache for an entity with the same keys, and will return it if it finds one. Otherwise, it will fallback to going to the data store, for that, it needs to build a LINQ expression dynamically.

Sample usage:

//strongly typed version

var blog = ctx.Blogs.Find(1);

 

//loosely typed version

var blog = (Blog) ctx.Find(typeof(Blog), 1);

Getting an Entity’s Id Programmatically

This is also important: getting an entity’s id values dynamically, that is, without knowing beforehand what are the properties (normally just one) that keeps them. Pretty simple:

public static object[] GetEntityKey<T>(this DbContext context, T entity) where T : class

{

    var state = context.Entry(entity);

    var metadata = state.Metadata;

    var key = metadata.FindPrimaryKey();

    var props = key.Properties.ToArray();

 

    return props.Select(x => x.GetGetter().GetClrValue(entity)).ToArray();

}

Here’s how to use:

Blog blog = ...;

var id = ctx.GetEntityKey(blog);

Reload

The Reload method tells Entity Framework to re-hydrate an already loaded entity from the database, to account for any changes that might have occurred after the entity was loaded by EF. In order to properly implement this, we will first need to define the two methods shown above (no need for the loosely-coupled version of Find, though):

public static TEntity Reload<TEntity>(this DbContext context, TEntity entity) where TEntity : class

{

    return context.Entry(entity).Reload();

}

 

public static TEntity Reload<TEntity>(this EntityEntry<TEntity> entry) where TEntity : class

{

    if (entry.State == EntityState.Detached)

    {

        return entry.Entity;

    }

 

    var context = entry.Context;

    var entity = entry.Entity;

    var keyValues = context.GetEntityKey(entity);

 

    entry.State = EntityState.Detached;

 

    var newEntity = context.Set<TEntity>().Find(keyValues);

    var newEntry = context.Entry(newEntity);

 

    foreach (var prop in newEntry.Metadata.GetProperties())

    {

        prop.GetSetter().SetClrValue(entity, prop.GetGetter().GetClrValue(newEntity));

    }

 

    newEntry.State = EntityState.Detached;

    entry.State = EntityState.Unchanged;

 

    return entry.Entity;

}

Here’s two versions of Reload: one that operates on an existing EntityEntry<T>, and another for DbContext; one can use them as:

Blog blog = ...;

 

//first usage

ctx.Entry(blog).Reload();

 

//second usage

ctx.Reload(blog);

You will notice that the code is updating the existing instance that was already loaded by EF, if any, and setting its state to Unchanged, so any changes made to it will be lost.

Local

EF Core 1.0 also lost the Local property, which allows us to retrieve cached entities that were previously loaded. Here’s one implementation of it:

public static IEnumerable<EntityEntry<TEntity>> Local<TEntity>(this DbSet<TEntity> set, params object [] keyValues) where TEntity : class

{

    var context = set.GetInfrastructure<IServiceProvider>().GetService<DbContext>();

    var entries = context.ChangeTracker.Entries<TEntity>();

 

    if (keyValues.Any() == true)

    {

        var entityType = context.Model.FindEntityType(typeof(TEntity));

        var keys = entityType.GetKeys();

        var i = 0;

 

        foreach (var property in keys.SelectMany(x => x.Properties))

        {

            var keyValue = keyValues[i];

            entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

            i++;

        }

    }

 

    return entries;

}

the keyValues parameter is optional, it is the entity’s identifier values. If not supplied, Local will return all entries of the given type:

//all cached blogs

var cachedBlogs = ctx.Set<Blog>().Local();

 

//a single cached blog

var cachedBlog = ctx.Set<Blog>().Local(1).SingleOrDefault();

Evict

Entity Framework has no Evict method, unlike NHibernate, but it is very easy to achieve the same purpose through DbEntityEntry.State (now EntityEntry.State, in EF Core). I wrote an implementation that can evict several entities or one identified by an identifier:

public static void Evict<TEntity>(this DbContext context, TEntity entity) where TEntity : class

{

    context.Entry(entity).State = EntityState.Detached;

}

 

public static void Evict<TEntity>(this DbContext context, params object [] keyValues) where TEntity : class

{

    var tracker = context.ChangeTracker;

    var entries = tracker.Entries<TEntity>();

 

    if (keyValues.Any() == true)

    {

        var entityType = context.Model.FindEntityType(typeof (TEntity));

        var keys = entityType.GetKeys();

 

        var i = 0;

 

        foreach (var property in keys.SelectMany(x => x.Properties))

        {

            var keyValue = keyValues[i];

 

            entries = entries.Where(e => keyValue.Equals(e.Property(property.Name).CurrentValue));

 

            i++;

        }

    }

 

    foreach (var entry in entries.ToList())

    {

        entry.State = EntityState.Detached;

    }

}

As usual, an example is in order:

var blog = ...;

var id = ctx.GetEntityKey(blog);

 

//evict the single blog

ctx.Evict(blog);

 

//evict all blogs

ctx.Evict<Blog>();

 

//evict a single blog from its identifier

ctx.Evict<Blog>(id);

Conclusion

Granted, some of the missing functionality will give developers a major headache, but, even with what we have, it’s not impossible to go around them. Of course, this time, it was simple stuff, but in future posts I will try to address some more complex features.

Entity Framework Pitfalls: Attaching New Entities With Existing Related Ones

One of the patterns in EF 6.x for attaching new entities to a context is to simply change it’s state to Added:

ctx.Entry(myEntity).State = EntityState.Added;

Entity Framework 6.x will traverse the entity graph of all the related entities and set all their states to Added too. This might be a problem.

Imagine we want to attach a disconnected (new) entity that is linked to an existing one, for which we already have a reference. In this case, we don’t want this reference to be added, because doing so will raise a violation on the database and it will come out as an exception.

What we need to do is to explicitly set the state of any of these existing instances to Unchanged. Fortunately, Entity Framework Core will solve this with the introduction of a new TrackGraph API.

Thanks for Tony Sneed (@tonysneed) for reminding me.

Entity Framework Pitfalls: Cascade Deletes

Introduction

Entity Framework supports cascading deletes for all of its associations:

  • One to one
  • One to many
  • Many to many

Meaning, when we remove an entity, it will automatically descend to its dependent entities (cascade) and delete them too.

Of course, cascading deletes of many to one really does not make much sense. The problem with cascade deletes configuration in EF is, sometimes it cannot be done with attributes, which is a mapping mechanism that most people like and use, and the different associations need different approaches.

One to One

For one to one relations, we need to use code mappings, say, we have an entity Master associated with a dependent entity Detail:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

    modelBuilder

        .Entity<Master>()

        .HasOptional(x => x.Detail)

        .WithRequired(x => x.Master)

        .WillCascadeOnDelete(true);

 

    base.OnModelCreating(modelBuilder);

}

Deleting a Master will also delete the Detail, but, of course, not the other way around. If you are curious, EF does this through an ON DELETE CASCADE INDEX, so it is done by the database, not by EF – more on this later.

image

One to Many

We just need to mark the one endpoint with a [Required] attribute, like in a Detail entity that is a child of a Master:

public class Detail

{

    public int Id { get; set; }

 

    [Required]

    public virtual Master Master { get; set; }

}

This way, when we delete the Master entity, it will first delete all of its related Detail entities. This is also achieved through the automatically created ON DELETE CASCADE INDEX.

It is also certainly possible to achieve this using code configuration, but not really necessary – and more verbose:

protected override void OnModelCreating(DbModelBuilder modelBuilder)

{

    modelBuilder

        .Entity<Master>()

        .HasMany(x => x.Details)

        .WithRequired(x => x.Master)

        .WillCascadeOnDelete();

 

    base.OnModelCreating(modelBuilder);

}

Many to Many

This one is the best: guess what, we don’t have to do anything, it just works out of the box!

Conclusion

Because Entity Framework relies on INDEXes to cascade the deletes, you cannot just change the code mappings after you created the model – either by adding attributes or through fluent configuration – and expect things to work. If you do, you will likely need to update the database. Do so by creating and applying a new migration. One thing that is still (as of EF 6.x) not supported is deleting orphans, but I already talked about it. EF Core will handle it properly.

Entity Framework Pitfalls: TransactionScope

Most people using Entity Framework use the TransactionScope API to manage database transactions. This is a powerful API, that can be used to enlist .NET APIs and even WS-*-compatible web services in transactions, that may well be distributed. Microsoft used to recommend it for working with EF, but isn’t doing it anymore, or, at least, developers need to understand a thing or two.

Most modern APIs offer asynchronous methods in addition, or instead, of blocking ones, and Entity Framework is a good example – just think of SaveChangesAsync, FindAsync and ToListAsync. The problem with TransactionScope prior to version 4.5.1 was that it didn’t handle well transaction-enabled methods running in other threads – which is what EF’s asynchronous methods do. In this version, Microsoft introduced the

TransactionScopeAsyncFlowOption flag, which can be used to tell TransactionScope to flow transactions across async threads.

Also, if we open two database connections inside a TransactionScope, the transaction gets automatically promoted to a distributed one. The problem is, distributed transactions require Microsoft Distributed Transaction Coordinator service running, and it is not available in Azure, for example (Web Apps).

So, the key here is: if we cannot be certain of the environment where EF will run, which may include pre-.NET 4.5.1 or Azure, we should use explicit transactions instead. It’s not that difficult, it’s just a matter of calling Database.BeginTransaction() and either committing or rolling back/disposing of the returned object when we are done with it.

Entity Framework 7: What’s New?

The Microsoft WebCamp 2015 event (Portugal) is now over! Another day packed with lots of interesting sessions and, above all, interesting people! Smile

As usual, here is the slide deck for my presentation, Entity Framework 7: What’s New?. In the shared folder you will also find the sample code. *Please*, do drop me a line if you want to discuss any of the topics!

Thanks to all who dropped by, and to Luís Calado (@elcalado) and João Almeida (@jalmeida) from Microsoft Portugal for inviting me! Winking smile

Lesser-Known NHibernate Features: Executable HQL

var records = session.CreateQuery("update Person p set p.Email = p.Email + p.Username + '@somedomain.com' where p.Email is null").ExecuteUpdate();

What happens when you need to bulk change a lot of records on the database? The unwary novice might be tempted to load data from the database into class instances, change them and then either rely on change tracking to eventually make the changes persistent or even worse, explicitly do an update on every possibly changed entity. The non-novice readers should now rolling their eyes.

It so happens that NHibernate offers a great alternative in the form of executable HQL. Basically, it is HQL for doing bulk changes: inserts, updates and deletes.

HQL Inserts have a small gotcha: they need to come from selects. Here’s an example:

var records = session.CreateQuery("insert into Account (Name, Email, Birthday) select p.Name, p.Email, p.Birthday from Person").ExecuteUpdate();

Here is an update:

var records = session.CreateQuery("update Person p set p.Email = p.Email + p.Username + '@somedomain.com' where p.Email is null").ExecuteUpdate();

Two problems arise:

  • Cannot do joins with updates;
  • Does not update version properties.

The second one is easy to solve:

var records = session.CreateQuery("update versioned Person p set p.Email = p.Email + p.Username + '@somedomain.com' where p.Email is null").ExecuteUpdate();

Noticed the versioned keyword? This tells NHibernate to do the right thing: update the version on each affected entity, of the entity is versioned.

The final one is deletes:

var records = session.CreateQuery("delete Product p where size(p.Sales) = 0").ExecuteUpdate();

The only problem with this is that it does not cascade. You need to find another solution.

A final word on this: you can, of course, specify parameters in your queries, like in the following example.

var records = session.CreateQuery("delete Product p where p.Price = :price").SetParameter("price", 0).ExecuteUpdate();

Entity Framework Pitfalls: DbConfiguration Classes Are Automatically Loaded

Entity Framework, since version 6, allows us to specify certain aspects of its configuration by code through a DbConfiguration-derived class. This configuration can be specified in one of three ways:

However, if there is a DbConfiguration-derived class in the same assembly as your DbContext, it will be automatically set as the configuration class, provided that:

  • It is public;
  • It is non-abstract;
  • It has a public parameterless constructor.

So, a DbConfiguration in the same assembly as the DbContext is automatically loaded. If there is more than one, the DbContext constructor will throw an exception.