实体框架4.1通用存储库设置

时间:2013-06-20 21:21:17

标签: entity-framework generics repository-pattern

我是Entity Framework的新手,加入了一个使用通用存储库的项目,如下所示。存储库的设置方式是否有任何缺点?我注意到大多数教程都描述了基于通用基础存储库创建多个存储库,而不是拥有一个处理所有内容的通用存储库。

为了给出一些背景知识,这段代码是ASP.NET MVC 3网站的一部分,我们使用unity作为IOC容器。业务层中的所有组件都继承自通过构造函数注入IEntityRepository的基类。

这是通用存储库类

public class MyRepository
{
    private const string containerName = "myEntities";
    private readonly ObjectContext context;
    private readonly Hashtable objectSets;

    // Track whether Dispose has been called.
    private bool disposed;

    public MyRepository()
    {
        string connectionString = ConfigurationManager.ConnectionStrings[containerName].ConnectionString;

        context = new ObjectContext(connectionString) {DefaultContainerName = containerName};
        context.ContextOptions.LazyLoadingEnabled = true;
        context.ContextOptions.ProxyCreationEnabled = true;

        objectSets = new Hashtable();
    }

    private ObjectSet<TEntity> GetObjectSet<TEntity>() where TEntity : class
    {
        ObjectSet<TEntity> objectSet;

        var type = typeof (TEntity);
        if (objectSets.ContainsKey(type))
        {
            objectSet = objectSets[type] as ObjectSet<TEntity>;
        }
        else
        {
            objectSet = context.CreateObjectSet<TEntity>();
            objectSets.Add(type, objectSet);
        }

        return objectSet;
    }

    public IQueryable<TEntity> GetAll<TEntity>(params string[] entities) where TEntity : class
    {
        ObjectQuery<TEntity> objectQuery = GetObjectSet<TEntity>();

        foreach (var entity in entities)
        {
            objectQuery = objectQuery.Include(entity);
        }

        return objectQuery;
    }


    public void Insert<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();
        objectSet.AddObject(entity);
    }

    public void Update<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();

        EntityKey key = objectSet.Context.CreateEntityKey(objectSet.EntitySet.Name, entity);

        object originalItem;
        if (objectSet.Context.TryGetObjectByKey(key, out originalItem))
        {
            objectSet.ApplyCurrentValues(entity);
        }
        else
        {
            objectSet.Attach(entity);
            objectSet.ApplyCurrentValues(entity);
        }
    }

    public void Delete<TEntity>(TEntity entity) where TEntity : class
    {
        ObjectSet<TEntity> objectSet = GetObjectSet<TEntity>();
        objectSet.DeleteObject(entity);
    }

    public void SaveChanges()
    {
        try
        {
            context.SaveChanges();
        }
        catch (Exception ex)
        {
            ex.ToString();
            throw ex;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        // Take yourself off the Finalization queue 
        // to prevent finalization code for this object
        // from executing a second time.
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        // Check to see if Dispose has already been called
        if (!disposed)
        {
            if (disposing)
            {
                context.Dispose();
            }
        }
        disposed = true;
    }

    ~MyRepository()
    {
        Dispose(false);
    }
}

这是用于公开方法的接口:

public interface IEntityRepository : IDisposable
{
    void Delete<TEntity>(TEntity entity) where TEntity : class;

    IQueryable<TEntity> GetAll<TEntity>(params string[] entities) where TEntity : class;

    void Insert<TEntity>(TEntity entity) where TEntity : class;

    void Update<TEntity>(TEntity entity) where TEntity : class;

    void SaveChanges();
}

1 个答案:

答案 0 :(得分:1)

使用通用存储库而不是每个Aggregate root具有一个具体的存储库实现的主要缺点是,您无法为特定用法创建特定方法。

让所有存储库从基础存储库继承后,您可以创建类似:GetProductsInsSock()或类似UpdateOnlyProductsThatSatisfySomething()的方法。

但是有一些解决方法可用! ; - )

继续使用您的通用存储库(如果它适合您的团队),您可能必须添加的唯一方法是接受Specification作为参数的方法。正如Eric Evans和Martin Fowler所说:

  

规范的核心思想是分离如何陈述   从候选对象匹配候选对象   对

在您的情况下,它可以作为过滤器来检索正确的实体,而无需创建特定的方法。

您只需将其添加到IRepository界面:

即可
IEnumerable<T> Find(Specification<T> predicate);

Repository课程中的方法实现如下:

public class Repository<T> : IRepository<T> where T : class
{
  public Repository(IDbContext context)
  {
    _context = context;
    _dbset   = context.Set<T>();
  }

  // some code...

  public IEnumerable<T> Find(Specification<T> specification)
  {
    return _dbset.Where(specification.Predicate);
  }

  // some code...
}

Specification类可能如下所示:

public class Specification<T>
{
  public Specification(Expression<System.Func<T, bool>> predicate)
  {
    _predicate = predicate;
  }

  internal Expression<System.Func<T, bool>> Predicate
  {
    get { return _predicate; }
  }

  private readonly Expression<System.Func<T, bool>> _predicate;
}

一个电话示例:

var specification = ProductSpecification.InStock();
var product = Repository.Find(specification).FirstOrDefault();

最后,ProductSpecification类:

internal static class ActionSpecification
{
  internal static Specification<Product> InStock()
  {
    return new Specification<Product>(p => p.IsInStock == true);
  }
}