With .NET 4.0 right around the corner, I thought it would be cool to download Visual Studio 2010 beta 2 and start playing around with the next release of Entity Framework.
The initial release of Entity Framework came with a great deal of criticism. To make matters worse, there was a large uproar when it was rumored that Microsoft would be abandoning LINQ to SQL, in favor of Entity Framework. This was because, at the time, many developers felt Entity Framework was an inferior technology to LINQ to SQL. To set things right, Microsoft proactively moved forward with improving Entity Framework, in time for the 4.0 release of the .NET Framework. This is good news because my initial impressions, so far, have been nothing but positive.
One of the concerns that many developers had with the initial Entity Framework release was the difficulty in building a repository. Having said that, the first thing I did upon opening Visual Studio 2010 was to build one. Soon into my test project, I noticed some interesting things. The first thing that really caught my attention was the IObjectSet interface, which provides the ability to modify data objects. Every bit as important, the ObjectContext class now has a generic CreateObjectSet() method. As soon as I saw these two things, I realized the potential, not only for creating a repository, but for creating a generic repository. That’s right, one generic class that can perform all of the CRUD operations for your entire application.
To start out, I built a generic interface for our repository. Notice that with the exception of the two SaveChanges() methods, every method either takes an object of type T as a parameter, or returns an object (either a collection or a single entity), also of type T.
public interface IRepository : IDisposable where T : class
{
IQueryable Fetch();
IEnumerable GetAll();
IEnumerable Find(Func<T, bool> predicate);
T Single(Func<T, bool> predicate);
T First(Func<T, bool> predicate);
void Add(T entity);
void Delete(T entity);
void Attach(T entity);
void SaveChanges();
void SaveChanges(SaveOptions options);
}
Moving onward, implementing the interface was a breeze. Take note of the constructor and the call to CreateObjectSet() off of the global _context variable. This is the magic that makes the generic repository possible.
///
/// A generic repository for working with data in the database
///
/// A POCO that represents an Entity Framework entity
public class DataRepository : IRepository where T : class
{
///
/// The context object for the database
///
private ObjectContext _context;
///
/// The IObjectSet that represents the current entity.
///
private IObjectSet _objectSet;
///
/// Initializes a new instance of the DataRepository class
///
public DataRepository()
: this(new AdventureWorksEntities())
{
}
///
/// Initializes a new instance of the DataRepository class
///
/// The Entity Framework ObjectContext
public DataRepository(ObjectContext context)
{
_context = context;
_objectSet = _context.CreateObjectSet();
}
///
/// Gets all records as an IQueryable
///
/// An IQueryable object containing the results of the query
public IQueryable Fetch()
{
return _objectSet;
}
///
/// Gets all records as an IEnumberable
///
/// An IEnumberable object containing the results of the query
public IEnumerable GetAll()
{
return GetQuery().AsEnumerable();
}
///
/// Finds a record with the specified criteria
///
/// Criteria to match on
/// A collection containing the results of the query
public IEnumerable Find(Func<T, bool> predicate)
{
return _objectSet.Where(predicate);
}
///
/// Gets a single record by the specified criteria (usually the unique identifier)
///
/// Criteria to match on
/// A single record that matches the specified criteria
public T Single(Func<T, bool> predicate)
{
return _objectSet.Single(predicate);
}
///
/// The first record matching the specified criteria
///
/// Criteria to match on
/// A single record containing the first record matching the specified criteria
public T First(Func<T, bool> predicate)
{
return _objectSet.First(predicate);
}
///
/// Deletes the specified entitiy
///
/// Entity to delete
/// if is null
public void Delete(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.DeleteObject(entity);
}
///
/// Deletes records matching the specified criteria
///
/// Criteria to match on
public void Delete(Func<T, bool> predicate)
{
IEnumerable records = from x in _objectSet.Where(predicate) select x;
foreach (T record in records)
{
_objectSet.DeleteObject(record);
}
}
///
/// Adds the specified entity
///
/// Entity to add
/// if is null
public void Add(T entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
_objectSet.AddObject(entity);
}
///
/// Attaches the specified entity
///
/// Entity to attach
public void Attach(T entity)
{
_objectSet.Attach(entity);
}
///
/// Saves all context changes
///
public void SaveChanges()
{
_context.SaveChanges();
}
///
/// Saves all context changes with the specified SaveOptions
///
/// Options for saving the context
public void SaveChanges(SaveOptions options)
{
_context.SaveChanges(options);
}
///
/// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
///
/// A boolean value indicating whether or not to dispose managed resources
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_context != null)
{
_context.Dispose();
_context = null;
}
}
}
}
To use it, you need only instantiate the generic repository of whichever entity type you wish to query. For example, using Adventure Works, you could bind to a GridView on an ASP.NET web form, with the following:
using (IRepository<Employee> repository = new DataRepository<Employee>())
{
this.GridView1.DataSource = from x in repository.Fetch()
select new
{
x.MaritalStatus,
x.Contact.FirstName,
x.Contact.LastName,
x.BirthDate
};
this.GridView1.DataBind();
}
To change the table that you wish to query, simply change the type instantiated.
Conclusion
Hopefully, you have gotten a little insight into the power that the new Entity Framework has to offer. I really believe that Microsoft has made great progress in this release. For those that were turned off by eariler versions, I urge you to give Entity Framework another go with the 4.0 release.
