Search
Close this search box.

Creating a Generic Entity Framework 4.0 Repository

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<TEntity>() 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<T> : IDisposable where T : class

{

    IQueryable<T> Fetch();

    IEnumerable<T> GetAll();

    IEnumerable<T> 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.

/// <summary>
/// A generic repository for working with data in the database
/// </summary>
/// <typeparam name="T">A POCO that represents an Entity Framework
/// entity</typeparam>
public class DataRepository<T> : IRepository<T>
    where T : class

              {
  /// <summary>
  /// The context object for the database
  /// </summary>
  private ObjectContext _context;

  /// <summary>
  /// The IObjectSet that represents the current entity.
  /// </summary>
  private IObjectSet<T> _objectSet;

  /// <summary>
  /// Initializes a new instance of the DataRepository class
  /// </summary>
  public DataRepository()

      : this(new AdventureWorksEntities())

  {}

  /// <summary>
  /// Initializes a new instance of the DataRepository class
  /// </summary>
  /// <param name="context">The Entity Framework ObjectContext</param>
  public DataRepository(ObjectContext context)

  {
    _context = context;

    _objectSet = _context.CreateObjectSet<T>();
  }

  /// <summary>
  /// Gets all records as an IQueryable
  /// </summary>
  /// <returns>An IQueryable object containing the results of the
  /// query</returns>
  public IQueryable<T> Fetch()

  {
    return _objectSet;
  }

  /// <summary>
  /// Gets all records as an IEnumberable
  /// </summary>
  /// <returns>An IEnumberable object containing the results of the
  /// query</returns>
  public IEnumerable<T> GetAll()

  {
    return GetQuery().AsEnumerable();
  }

  /// <summary>
  /// Finds a record with the specified criteria
  /// </summary>
  /// <param name="predicate">Criteria to match on</param>
  /// <returns>A collection containing the results of the query</returns>
  public IEnumerable<T> Find(Func<T, bool> predicate)

  {
    return _objectSet.Where<T>(predicate);
  }

  /// <summary>
  /// Gets a single record by the specified criteria (usually the unique
  /// identifier)
  /// </summary>
  /// <param name="predicate">Criteria to match on</param>
  /// <returns>A single record that matches the specified criteria</returns>
  public T Single(Func<T, bool> predicate)

  {
    return _objectSet.Single<T>(predicate);
  }

  /// <summary>
  /// The first record matching the specified criteria
  /// </summary>
  /// <param name="predicate">Criteria to match on</param>
  /// <returns>A single record containing the first record matching the
  /// specified criteria</returns>
  public T First(Func<T, bool> predicate)

  {
    return _objectSet.First<T>(predicate);
  }

  /// <summary>
  /// Deletes the specified entitiy
  /// </summary>
  /// <param name="entity">Entity to delete</param>
  /// <exception cref="ArgumentNullException"> if <paramref name="entity"/> is
  /// null</exception>
  public void Delete(T entity)

  {
    if (entity == null)

    {
      throw new ArgumentNullException("entity");
    }

    _objectSet.DeleteObject(entity);
  }

  /// <summary>
  /// Deletes records matching the specified criteria
  /// </summary>
  /// <param name="predicate">Criteria to match on</param>
  public void Delete(Func<T, bool> predicate)

  {
    IEnumerable<T> records = from x in _objectSet.Where<T>(predicate) select x;

    foreach (T record in records)

    {
      _objectSet.DeleteObject(record);
    }
  }

  /// <summary>
  /// Adds the specified entity
  /// </summary>
  /// <param name="entity">Entity to add</param>
  /// <exception cref="ArgumentNullException"> if <paramref name="entity"/> is
  /// null</exception>
  public void Add(T entity)

  {
    if (entity == null)

    {
      throw new ArgumentNullException("entity");
    }

    _objectSet.AddObject(entity);
  }

  /// <summary>
  /// Attaches the specified entity
  /// </summary>
  /// <param name="entity">Entity to attach</param>
  public void Attach(T entity)

  {
    _objectSet.Attach(entity);
  }

  /// <summary>
  /// Saves all context changes
  /// </summary>
  public void SaveChanges()
  {
    _context.SaveChanges();
  }

  /// <summary>
  /// Saves all context changes with the specified SaveOptions
  /// </summary>
  /// <param name="options">Options for saving the context</param>
  public void SaveChanges(SaveOptions options)

  {
    _context.SaveChanges(options);
  }

  /// <summary>
  /// Releases all resources used by the
  /// WarrantManagement.DataExtract.Dal.ReportDataBase
  /// </summary>
  public void Dispose()
  {
    Dispose(true);

    GC.SuppressFinalize(this);
  }

  /// <summary>
  /// Releases all resources used by the
  /// WarrantManagement.DataExtract.Dal.ReportDataBase
  /// </summary>
  /// <param name="disposing">A boolean value indicating whether or not to
  /// dispose managed resources</param>
  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.

This article is part of the GWB Archives. Original Author: Sean’s Blog

Related Posts