Ok… It wasn’t really that bad, but it did take some effort. Here was my objective: Now that MVC (ASP.NET Model-View-Controller) 1.1 has been released (not sure how I missed that) to work with Visual Studio 2010 and .NET 4.0 migrate my evolving website to use the .NET 4.0 beta.
I was able to get it all to work. The biggest speed bump was the fact that I used the MVC Futures (Microsoft.Web.Mvc.dll) feature called Html.RenderAction. For some of the details on what I did to resolve that you can visit the forums.asp.net.
Entity Framework – From Repository to IObjectSet<T>
This was the biggest change and a welcome one. The code I’ll cover here results from mimicking Microsoft. I still want my .NET 3.5 code to work, but I also want to minimize the differences.
Repository
So let me start with what sort of data access I used yesterday. Having read Steve Sanderson’s Pro ASP.NET MVC Framework I use “repositories” for my collections of “things”. That works nicely for unit testing. I can have IWineListRepository and then implement one using the Entity Framework and another one that is a Fake.
The Repository Disadvantage
However, there is one significant disadvantage from that approach. The collections in the repository are returned as IQueryable<T> – very nice for working with LINQ. And it’s fine for small collections. But what if you have large collections (of course I don’t – but what if)? The disadvantage is that you would pull ALL the records from the database into your repository THEN you would run your LINQ query or use your Lambda expression to sort it.
Entity Framework 1.0 Disadvantage
If I use the Entity Framework, then my collections are returned using ObjectQuery. If I use LINQ on the ObjectQuery then it will be translated to SQL and run on the SQL Server. For example, if I were Amazon and had millions of books, the repository would pull all the books back, then find the one(s) I wanted. But using the ObjectQuery I can do all that on the SQL Server. Ok.. clearly that’s not the disadvantage… The disadvantage of using the ObjectQuery is that I cannot easily unit test it like I can the repository. For that the repository Steve describes is vastly superior.
Entity Framework 4.0 and the IObjectSet – Best of Both Worlds!
Entity Framework (EF) 4.0 (yes, they skipped from 1.0 to 4.0 to be versioned with .NET 4.0) introduces IObjectSet<T>. And in EF 4.0 ObjectQuery<T> inherits from IObjectSet<T>! So now instead of having IWineListRepository I can use IObjectSet<VarietalWineList>. Then when it comes to implementation if I want only red wines, I can put a LINQ query together against IObjectSet<T> and only pull back red wines! But if I want to unit test, I can develop my own implementation of IObjectSet<T>.
MemoryObjectSet<T>
I actually wish that Microsoft would ship a class called MemoryObjectSet<T> with the framework. It would make unit testing much easier and then not EVERY developer in the .NET world would need to implement their own. Here is my code for the MemoryObjectSet<T> which is an in-memory version of IObjectSet<T>. In this code you’ll see something that’s excluded. I trust that in subsequent versions they will implement Detach as part of the IObjectSet<T> interface. I’ve already submitted this request to Microsoft Connect.
Here’s the code:
#region using statements
using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;
#endregion
namespace Karlz.Data.Objects
{
///
<summary>
/// This implements the IObjectSet interface so that we can have
/// ObjectSets that are in-memory only representations. This will
/// allow us to create true unit tests rather than having to hit
/// the database for all the Entity Framework tests.
///
</summary>
///
<typeparam name=”T”></typeparam>
[System.Diagnostics.CodeAnalysis.SuppressMessage(“Microsoft.Naming”,
“CA1710:IdentifiersShouldHaveCorrectSuffix”,
Justification = “This is an in-memory version of the ObjectSet<T>. Consumers would be confused if it was MemoryObjectCollection.”)]
public
class
MemoryObjectSet<T> : IObjectSet<T> where T : class
{
private
List<T> _repository = new
List<T>();
public
IQueryable<T> RepositoryQuery
{
get
{
return _repository.AsQueryable<T>();
}
}
public
Type ElementType
{
get { return RepositoryQuery.ElementType; }
}
public System.Linq.Expressions.Expression Expression
{
get { return RepositoryQuery.Expression; }
}
public System.Linq.IQueryProvider Provider
{
get { return RepositoryQuery.Provider; }
}
public
void AddObject(T entity)
{
_repository.Add(entity);
}
public
void Attach(T entity)
{
if (!_repository.Contains(entity))
{
_repository.Add(entity);
}
}
// TODO: Is there a reason that Microsoft does not support
// Detach in the IObjectSet interface?
#if NET35
public void Detach(T entity)
{
if (_repository.Contains(entity))
{
_repository.Remove(entity);
}
}
#endif
public
void DeleteObject(T entity)
{
_repository.Remove(entity);
}
public
IEnumerator<T> GetEnumerator()
{
return _repository.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _repository.GetEnumerator();
}
}
}
I also implemented IObjectSet<T> and ObjectSet in .NET 3.5 so that I could use the same code for 3.5 and 4.0. This post is already long… Just contact me if you want to see that code.
Best of Both Worlds
So now, using the Unity Framework I can easily switch between the two implementations as Steve describes in his book (except he uses Castle Windsor for IoC containers).
Unit Testing is Much Better
This one small change in EF really improves testability. I know the EF team have made many other changes, but I’ve not really been able to experience them so far. I’m not sure if they will be in future releases, but I’ll do some more investigation.
Leave a Reply