Entity Framework – Some common hurdles
I just read a post “Entity Framework - Disappointment” where a decision was made to ditch the EF because of some deficiencies. I want to emphasize that I know nothing about that specific project and the point of this post is not by any means to “attack” their approach. It is not my intention to pick on that specific post since I’ve seen similar complaints elsewhere. It did catch my attention though. I started with a comment, but it quickly became too long.
My first reaction when I read the list was that I wanted to check how difficult it would be to deal with these issues in our repository implementation.
The list of deficiencies:
- No eager loading. Need to specify .Include(“”) for every query.
- No way to make to turn change tracking on/off except from changing every query.
- A bug that prevents simple queries where nvarchar columns are used in the criteria.
- A designer error with a cryptic error message.
Before I go over the list of issues, it is important to note that in our whole system which has many hundred queries there is only one ObjectQuery<T>. What makes each query return different data are the specifications passed to the GetXXX() methods.
Every query in the repository is created by a method that looks similar to the following. The real implementation is a little bit more complex than this.
/// <summary>
/// Create a query for type T.
/// </summary>
private ObjectQuery<T> CreateQuery<T>()
{
ObjectQuery<T> query;
string entitySetName = GetEntitySetName(typeof(T));
query = ObjectContext.CreateQuery<T>(entitySetName);
return query;
}
No Eager Loading
This is an issue that has been criticized a lot since the initial release of the Entity Framework. Since I didn’t know how to achieve this, I’ll walk us through the exploratory steps towards a somewhat simplistic solution.
The eager loading requirements I defined were as following.
- A property on the repository should allow the developer consuming the repository to opt in/out for eager loading for all subsequent queries.
- No additional parameters should be required. (No use of the IncludeBuilder mentioned in my previous post on the repository)
- The eager load will only load related entities one level deep.
As you might know, the Entity Framework ObjectContext contains metadata. I was convinced that by exploring the metadata I would find a way to extract a list of related entities based on the type requested from the repository. After spending a few minutes in the debugger looking at a loaded ObjectContext I found that the MetaDataWorkspace contains all the information we need. Now we only need to write the code…
Here’s the method that retrieves the navigation values that we will need to insert into the calls to .Include(“”).
private IEnumerable<string> GetEntitySetNavigations(EntitySet entitySet)
{
return entitySet.ElementType.NavigationProperties.Select(p => p.Name);
}
We can now change the CreateQuery() to include the following.
if (EagerLoad)
{
foreach (string navigation in GetEntitySetNavigations(entitySet)
{
query = query.Include(navigation);
}
}
return query;
That’s it. Eager loading by setting a property on the repository.
No property to turn change tracking off
Since the property that determines change tracking is a property of the ObjectQuery<T>() variable in CreateQuery, we can solve the tracking issue by adding a property to the repository as well.
public bool TrackChanges { get; set; }
We now need to check this property in the CreateQuery() method.
We’ll change the last line of CreateQuery() to:
…
if (!TrackChanges)
query.MergeOption = MergeOption.NoTracking;
return query;
…
This effectively allow us to turn change tracking on and off as we see fit either on a per query or per session basis.
Can’t use nvarchar in criteria
We have not encountered this issue. I read the msdn forum thread referenced and I agree that this could be a showstopper.
Cryptic error messages by the designer.
I agree. The designer is not very helpful in telling you where things went wrong. In order to make things a little smoother, I usually add a few entities at a time. That way you narrow down where your issues are. Not that that makes dealing with the errors much fun, but I haven’t gotten hung up too much.
To summarize, the Entity Framework has a lot of power, and it does take some time to get familiar with it. But I guess that’s the case for any complex technology. I would have to disagree with the blanket statement that EF is a disappointment. It does have some rough edges, but that’s the case with many v1 technologies. If you don’t mind doing some plumbing code then EF can be a good choice IMHO.
BTW, It took much longer to write this post than to code changes to the repository. Maybe I should stick with coding. :-)