【问题标题】:Entity Framework 4.1 Generic Repository set up实体框架 4.1 通用存储库设置
【发布时间】:2013-06-20 21:21:16
【问题描述】:

我是 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();
}

【问题讨论】:

    标签: entity-framework generics repository-pattern


    【解决方案1】:

    使用通用存储库而不是每个聚合根都有具体的存储库实现的主要缺点是您无法为特定用途创建特定方法。

    让您的所有存储库都从基础存储库继承,您可以创建诸如 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);
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多