【问题标题】:How to create ORM independent generic repository? [closed]如何创建独立于 ORM 的通用存储库? [关闭]
【发布时间】:2014-06-08 08:59:05
【问题描述】:

这是我的通用基础存储库(它的一部分) - 使用 EntityFramework 6(是的,EF6 确实有一个通用存储库,但网络上有很多相互矛盾的意见是否仍然使用存储库模式,我将使用存储库)

 public class BaseRepository<T> : IBaseRepository<T> where T: class
    {
        private BlueWhaleEntities _dbContext;
        public BlueWhaleEntities DbContext { get; set; }
        public BaseRepository(BlueWhaleEntities dbContext )
        {
            _dbContext = dbContext;         
        }
//...More Add,Remove Generic Methods

我有一个更具体的PersonRespository

class PersonRepository: BaseRepository<Person>
    {
        public PersonRepository(BlueWhaleEntities blueWhaleEntities) : base(blueWhaleEntities)
        {
             //...Add,Remove methods for Person which override Generic repository's methods 
        }
    }

但是看看这个,存储库的一个目的是我可以更改 ORM..但是我在构造函数中注入了 EntityFramework DataContext,将我绑定到 EF。

那么我应该在构造函数中注入什么,然后如果需要,我可以稍后将 ORM 更改为其他东西(非常不可能,但理论上)?

谢谢

【问题讨论】:

标签: c# entity-framework repository


【解决方案1】:

不同的 ORM 有非常不同的 API。 EF 需要 DbContext,NHibernate 需要 Session,Dapper 需要普通 DbConnection,MongoDB 有 MongoDatabase。因此,不应该有一些基类适合不同 ORM 的任何可能的 API。如果您需要最佳性能,您甚至可以从 ORM 切换到纯 ADO。实际上,有时您甚至可以将对象存储在内存中。

你应该拥有的是接口,它将为不同的 ORM 实现

public interface IRepository<T>
{
    T GetById(object id);
    void Add(T entity);
    // ...
}

public interface IPersonRepository : IRepository<Person>
{
    IEnumerable<Person> GetPeopleByDepartment(int id);
}

它们的目的是向您的应用程序隐藏实现细节。依赖于这些接口。创建不同的实现。我通常将存储库实现移动到单独的程序集,其名称类似于 Foo.Persistence.EFFoo.Persistence.NHibernate。如果我需要不同的实现,我只需切换持久性程序集。

【讨论】:

  • 所以存储库并没有真正抽象 ORM,它们才是。因为这显然意味着每个 ORM 类型一个人存储库,这意味着如果您必须更改 ORM,则必须更改每个存储库。这违背了存储库的目的,不是吗?或者我在这里遗漏了什么:)
  • @iAteABug_And_iLiked_it 完全正确。对于不同的 ORM,存储库应该有不同的实现。没有其他办法。好吧,除了在单个怪物类中移动所有实现。好消息——你很少会切换实现(我在 6 年内做了两次)。这并没有违背存储库的目的。存储库的目的 - 对客户端隐藏数据访问实现细节。它不应该允许使用你想要的任何实现。
【解决方案2】:

我对这个问题有一个非常明确的解决方案。您应该分开 PersonRepository 实现。因此,您需要 ORM 独立的 IPersonRepository 接口。您可以从这个接口继承任何 ORM 特定的实现。

public interface IRepository<T>
{
    public TEntity Add(TEntity entity);
    //get T,
    //...
}
public interface EFRepositoryBase<TEntity, TContext> : IRepository<TEntity>
{
    public TEntity Add(TEntity entity)
    {
        using var context = new TContext();
        var addedEntity = context.Entry(entity);
        addedEntity.State = EntityState.Added;
        context.SaveChanges();
        return entity;
    }
  //get T,
  //...
}

您应该将通用 IRepository 和通用 EfRepositoryBase 保留在 Common 命名空间中。

public interface IPersonRepository : IRepository<Person>
{
}
public interface EfPersonRepository : EfRepositoryBase<Person, MyDbContext> IRepository<Person>
{
}
public interface MyOrmPersonRepository : IRepository<Person>
{
    public Person Add(Person p)
    {
        // MyOrm specific codes...
    }

    //get Person,
    //...
}

您应该将 PersonRepository、EfPersonRepository 和 MyOrmPersonRepository 保留在 Repositories 命名空间中。

public class PersonService
{
    IPersonRepository _personRepository;
    
    public Client(IPersonRepository personRepository)
    {
        _personRepository = personRepository;
    }

    public void AddPerson(Person p)
    {
        //business, validations, logging etc.
        //...
        _personRepository.Add(p);
    }
}
public class Client
{
    //...
    void Main()
    {
        //You should use DI tool in here
        
        PersonService personService = new PersonService(new EfPersonRepository());
        //or
        PersonService personService2 = new PersonService(new MyOrmPersonRepository());
        
        personService.AddPerson(new Person());
        //or
        personService2.AddPerson(new Person());

        //...
    }
}

您可以查看project 了解有关此架构设计的更多信息

【讨论】:

    猜你喜欢
    • 2015-05-26
    • 1970-01-01
    • 2012-01-17
    • 1970-01-01
    • 2015-05-07
    • 2019-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多