繁体   English   中英

存储库模式通用应用

[英]Repository Pattern universal application

几天前,当我开始使用Unity学习存储库模式时,我印象深刻的是,这种模式的主要好处是将数据层与业务层分离。

换句话说,如果需要更改方式,应用程序如何存储数据,这很容易,因为只有一个主要模型负责通信。

这意味着,如果应用程序当前将数据保存到序列化的XML文件中,那么更改此逻辑以连接到数据库并不是很困难。

我发现一些不错的演示也使用了Unit Of Work层,这似乎非常方便。 让我向您展示一些我的代码。

public class UnitOfWork : IUnitOfWork
{
    private readonly RepositoryContext _context;
    public IEmployeeRepository Employees { get; set; }

    public UnitOfWork(RepositoryContext context)
    {
        _context = context;
        Employees = new EmployeeRepository(_context);
    }


    public int Complete()
    {
        return _context.SaveChanges();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

主要存储库上下文:

public class RepositoryContext : DbContext
{
    public RepositoryContext() : base("name=RepositoryContext")
    {
    }

    public virtual DbSet<Employee> Employees { get; set; }
    public virtual DbSet<Equipment> Furniture { get; set; }
}

这是演示EmployeeRepository:

public class EmployeeRepository:Repository<Employee>, IEmployeeRepository
{
    public EmployeeRepository(RepositoryContext context) : base(context) { }

    public Employee GetEmployeeByName(string sName)
    {
        return MyContext.Employees.FirstOrDefault(n => n.Name == sName);
    }

    public RepositoryContext MyContext
    {
        get { return Context as RepositoryContext; }
    }
}

员工存储库派生自一个通用Repository ,如下所示:

public class Repository<T> : Interfaces.Repositories.IRepository<T> where T : class
{
    protected readonly DbContext Context;

    public Repository(DbContext context)
    {
        Context = context;
    }

    public void Add(T item)
    {
        Context.Set<T>().Add(item);
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return Context.Set<T>().Where(predicate);
    }

    public T Get(int ID)
    {
        return Context.Set<T>().Find(ID);
    }

    public IEnumerable<T> GetAll()
    {
        return Context.Set<T>().ToList();
    }

    public void Remove(T item)
    {
        Context.Set<T>().Remove(item);
    }
}

这是问题:

就我的理解而言,我们直接声明,在我们的Repository中,它需要构造函数DbContext ,该构造DbContext随后Add / Remove / Find在该特定类下的所有Add / Remove / Find函数中使用。

当前,该模型正在与数据库通信,但是如果我出于某种原因想要更改此模型以将数据保存在XML文件中,则必须完全重写所有的Repository类吗? 还是我在这里想念什么?

如果我错了并且很容易做到,请问有人可以告诉我如何更改代码,以便我们将值序列化为XML文件吗? 我试图更好地理解这种存储库模式,但是现在对我来说这是一个很大的混乱。

关于此事的任何帮助/建议将不胜感激。

我正在阅读这样的问题:

我如何抽象DbContext以便没有依赖关系?

我将把上下文抽象到接口,以尝试采用依赖关系反转原则

public interface IDbContext : IDisposable
{
    int SaveChanges();
    IDbSet<Employee> Employees { get; set; }
    IDbSet<Equipment> Furniture { get; set; }
}

public class RepositoryContext : DbContext, IDbContext
{
    public RepositoryContext() : base("name=RepositoryContext")
    {
    }

    public virtual DbSet<Employee> Employees { get; set; }
    public virtual DbSet<Equipment> Furniture { get; set; }
}

然后尝试注入IDbContext接口。 如评论中所述,您可能仍然需要重写部分仓库,但是如果新的数据层可以公开IDbSet,则您应该能够简单地更改IDbContext的实现。

public class Repository<T> : Interfaces.Repositories.IRepository<T> where T : class
{
    protected readonly IDbContext Context;

    public Repository(IDbContext context)
    {
        Context = context;
    }

    public void Add(T item)
    {
        Context.Set<T>().Add(item);
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> predicate)
    {
        return Context.Set<T>().Where(predicate);
    }

    public T Get(int ID)
    {
        return Context.Set<T>().Find(ID);
    }

    public IEnumerable<T> GetAll()
    {
        return Context.Set<T>().ToList();
    }

    public void Remove(T item)
    {
        Context.Set<T>().Remove(item);
    }
}

我还将研究在单独的类中抽象上下文创建的可能性。 如此处所述: 使用存储库模式,工作单元和统一性的实体框架

public interface IDbContextFactory
{
    IDbContext GetContext();
}

public class DbContextFactory : IDbContextFactory
{
    private readonly IDbContext _context;

    public DbContextFactory()
    {
        _context = new MyDbContext("ConnectionStringName");
    }

    public IDbContext GetContext()
    {
        return _context;
    }
}

这样,您可以将IDbContextFactory注入到工作单元中。 然后,您已经将DbContext抽象到DbContextFactory ,但是在DbContextFactory仍然有对DbContext的依赖。 这对于大多数人来说已经足够了,但是如果您想真正变成SOLID,那么也可以使用通用IInstanceFactory

    public interface IDbContextFactory
    {
        /// <summary>
        /// Creates a new context.
        /// </summary>
        /// <returns></returns>
        IDbContext GenerateContext();

        /// <summary>
        /// Returns the previously created context.
        /// </summary>
        /// <returns></returns>
        IDbContext GetCurrentContext();
    }

    public class DbContextFactory : IDbContextFactory
    {
        private readonly IInstanceFactory _instanceFactory;
        private IDbContext _context;

        public DbContextFactory(IInstanceFactory instanceFactory)
        {
            _instanceFactory = instanceFactory;
        }

        public IDbContext GenerateContext()
        {
            _context = _instanceFactory.CreateInstance<IDbContext>();
            return _context;
        }

        public IDbContext GetCurrentContext()
        {
            if (_context == null)
                _context = GenerateContext();
            return _context;
        }
    }

    /// <summary>
    /// Creates an instance of a specific model.
    /// </summary>
    public interface IInstanceFactory
    {
        /// <summary>
        /// Creates an instance of type T.
        /// </summary>
        T CreateInstance<T>();
    }

    /// <summary>
    /// Creates an instance based on the model defined by Unity.
    /// </summary>
    public class InstanceFactory : IInstanceFactory
    {
        private readonly IDictionary<Type, Func<object>> _funcs;

        public InstanceFactory(IEnumerable<Func<object>> createFunc)
        {
            // To remove the dependency to Unity we will receive a list of funcs that will create the instance.

            _funcs = new Dictionary<Type, Func<object>>();

            foreach (var func in createFunc)
            {
                var type = func.Method.ReturnType;
                _funcs.Add(type, func);
            }
        }

        /// <summary>
        /// Creates an instance of T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T CreateInstance<T>()
        {
            var func = _funcs[typeof(T)];
            return (T) func();
        }
    }

在我的Unity注册中:

    container.RegisterType<IDbContext, YourDbContext>(new TransientLifetimeManager());
    container.RegisterType<IInstanceFactory, InstanceFactory>(
            new InjectionConstructor(new List<Func<object>>
            {
                new Func<IDbContext>(() => container.Resolve<IDbContext>())
            }
        ));

现在,您已经将DbContext一直抽象到IoC,理论上可以在web.config中对其进行更改,而无需重新构建。 考虑因素? 好吧,考虑一下可读性与可维护性。 我更喜欢一个真正抽象的层,而其他人则认为这是没有必要的,因为EF已经是一个工作单元模式。 另外,可能会产生性能开销,而不是像现在那样仅创建DbContext 从更哲学的角度来看,有人可能会争辩说DbContext的抽象本身就是工作单元,因为它现在位于带有SaveChanges()的抽象层,可以像工作单元一样“传递”。 但是我把那个讨论留给你...

其中大部分是手工编写的,但是如果您决定抽象DbContext,希望它能对您有所帮助。

编辑:添加SaveChanges()到IDbContext

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM