簡體   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