如何创建独立于ORM的通用存储库

本文关键字:ORM 存储 独立 何创建 创建 | 更新日期: 2023-09-27 18:07:15

这是我的通用基础存储库(它的一部分)-使用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更改为其他东西(非常不可能,但理论上)?

谢谢

如何创建独立于ORM的通用存储库

不同的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。如果我需要不同的实现,我只需切换持久性程序集。

对于这个问题,我有一个非常明确的解决方案。您应该分离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());
        //...
    }
}

您可以查看此项目以获取有关此架构设计的更多信息