【问题标题】:Generic or specific repository when you need to support multiple ORM or sources?当您需要支持多个 ORM 或源时,是通用存储库还是特定存储库?
【发布时间】:2020-03-31 02:29:05
【问题描述】:

我需要通过实体框架和网络服务两种不同的方式来操作数据库中的一些数据。

为了简化,假设只有两个表 A 和 B。

我坚持这个设计。我是否应该简单地拥有两个派生自一个接口的类,这些接口公开了我想要的功能:

public interface IRepository
{
        bool AddA(A a);     
        bool RemoveA(A a);
        IEnumerable<A> GetAllA();
        bool AddB(B b);     
        bool RemoveB(B b);
        IEnumerable<B> GetAllB();
}

public class EfRepository : IRepository
{
        //actual code here
}

public class ServiceRepository : IRepository
{
        //actual code here
}

或者我应该尝试一种更通用的方法:

public interface IRepository<T>
{
        bool Add(T t);
        bool Remove(T t);
        IEnumerable<T> GetAll();
        bool Update(T t);

}

public class EfARepository: IRepository<A>
{
        //actual code here

}

public class EfBRepository : IRepository<B>
{
        //actual code here
}

public class ServiceARepository: IRepository<A>
{
        //actual code here

}

public class ServiceBRepository : IRepository<B>
{
        //actual code here
}

第二种方法似乎繁琐且重复,因为我并没有真正遵循通用存储库模式,因为我不确定它是否可行或值得付出努力,因为实体框架已经像存储库一样。或者这样的事情会更明智:

public class ARepository<Ef> : IRepository<A>
{
        //omitted
}
//or this
public class EfRepository<A> : IRepository<A>
{
        //omitted
}

但话又说回来,我无法将上下文(Ef 或服务)注入到类中,而 EF 的存储库(反之亦然)并没有多大意义。

请启发我并对上述设计发表评论,并为这种情况提出更好的方法或设计。一些与此相关的例子会很棒!

【问题讨论】:

    标签: c# oop generics design-patterns interface


    【解决方案1】:

    我在几个项目中使用了以下方法。这个例子稍微简化了一点。

    /// <summary>
    /// THE base class for all entities.
    /// </summary>
    /// <typeparam name="TKey">The type of the key for the entity.</typeparam>
    public abstract class Entity<TKey>
    {
      private TKey _id;
    
      public Entity() : this(default(TKey))
      {
      }
    
      public Entity(TKey id)
      {
        _id = id;
      }
    
      public Entity(Entity<TKey> source) : this(default(TKey))
      {
        if (source != null)
        {
          this._id = source._id;
        }
      }
    
      public TKey Id
      {
        get { return _id; }
        set { _id = value; }
      }
    
      public bool IsTransient()
      {
        return Id.Equals(default(TKey));
      }
    }
    
    public interface IRepository : IDisposable
    {
      bool Exists();
    
      void OpenConnection(); // helper
    
      void CreateIfNotExists();  // helper
    
      IQueryable<T> GetAll<T, TKey>() where T : Entity<TKey>;
    
      IQueryable<T> GetAllIncluding<T, TKey>(params Expression<Func<T, object>>[] includeProperties) where T : Entity<TKey>;
    
      IQueryable<T> SearchFor<T, TKey>(Expression<Func<T, bool>> predicate) where T : Entity<TKey>;
    
      T GetById<T, TKey>(TKey id) where T : Entity<TKey>;
    
      void Add<T, TKey>(T entity) where T : Entity<TKey>;
    
      void Update<T, TKey>(T entity) where T : Entity<TKey>;
    
      void Delete<T, TKey>(T entity) where T : Entity<TKey>;
    
      void Delete<T, TKey>(TKey id) where T : Entity<TKey>;
    
      void Save();
    
      void Delete();
    }
    

    然后您从Entity&lt;TKey&gt; 基类派生所有实体并实现存储库。

    public class MyRepository : IRepository
    {
      private DbContext _context;
    
      public EFRepository(DbContext context)
      {
          if (context == null)
            throw new ArgumentNullException("context");
    
          _context = context;
      }
    
      public bool Exists()
      {
        return _context.Database.Exists();
      }
      ...
      public IQueryable<T> GetAll<T, TKey>() where T : Entity<TKey>
      {
        return _context.Set<T>();
      }
    
      public IQueryable<T> GetAllIncluding<T, TKey>(params Expression<Func<T, object>>[] includeProperties) where T : Entity<TKey>
      {
        IQueryable<T> query = _context.Set<T>();
    
        foreach (var includeProperty in includeProperties)
        {
          query = query.Include(includeProperty);
        }
    
        return query;
      }
    
      public IQueryable<T> SearchFor<T, TKey>(Expression<Func<T, bool>> predicate) where T : Entity<TKey>
      {
        return _context.Set<T>().Where(predicate);
      }
    
      public T GetById<T, TKey>(TKey id) where T : Entity<TKey>
      {
        // use the static Equals method to accept null values
        return _context.Set<T>().FirstOrDefault(x => object.Equals(id, x.Id));
      }
    
      public void Add<T, TKey>(T entity) where T : Entity<TKey>
      {
        if (entity != null)
        {
          Context.Set<T>().Add(entity);  // new entity
        }
      }
    
      public void Update<T, TKey>(T entity) where T : Entity<TKey>
      {
        if (entity != null)
        {
          if (object.Equals(entity.Id, default(TKey)))
            Context.Set<T>().Add(entity);  // new entity
          else
            Context.Entry<T>(entity).State = EntityState.Modified;
        }
      }
      public void Save()
      {
        Context.SaveChanges();
      }
      ...
      public void Dispose()
      {
        Dispose(true);
      }
    
      protected virtual void Dispose(bool disposing)
      {
        if (disposing)
        {
          try
          {
            if (_context != null)
              _context.Dispose();
          }
          catch (Exception ex)
          {
            Debug.WriteLine("MyRepository.Dispose exception:" + ex);
          }
        }
      }
    }
    
    public class MyUser : Entity<int>
    {
      public MyUser()
      {
        Name = null;
      }
    
      public MyUser(string user)
      { 
        Name = user;
      }
    
      public MyUser(MyUser source) : base(source)
      {
        if (source != null)
        {
          Name = Helpers.SafeCopy(source.Name);
        }
      }
    
      public string Name { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-01-17
      • 2013-12-29
      • 2010-09-20
      • 2015-08-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-10
      • 1970-01-01
      • 2012-08-20
      相关资源
      最近更新 更多