使用反射的通用存储库周围的通用包装

时间:2014-03-22 19:51:46

标签: c# generics design-patterns reflection n-tier-architecture

我试图在n层体系结构中练习松散耦合并分离所有内容,但我坚持 - 我相信 - 基本的东西。我的头号问题是参考。我不断在程序集之间移动类,因为A类需要B类,但是无法到达它,所以让我们移动B类 - 然后我打破C类。

这是我能想到的最好的。

第1步:架构

Project.Data

  • 实体(POCO)

Project.DataAccess

  • 上下文
  • 迁移
  • 存储库
  • 工作单元
  • 的ViewModels

Project.Web

  • 控制器
  • 浏览

步骤2:使用Project.DataAccess作为演示文稿和数据

之间的粘合剂

我正在使用工作单元模式,但这需要访问POCO,因此我无法在控制器中使用UoW。因此,我认为创建名为ViewModelService的包装器/服务是一个很好的计划。此服务实例化UoW并将AutoMapped Viewmodels返回给我的控制器。

然而......

我的UoW / Repository模式是通用的,所以我也试图使我的服务也通用。

IRepository

public interface IRepository<TObject>
{
    IQueryable<TObject> All();
    IQueryable<TObject> Filter(Expression<Func<TObject, bool>> predicate);

    IQueryable<TObject> Filter<TKey>(Expression<Func<TObject, bool>> filter,
        out int total, int index = 0, int size = 50);

    bool Contains(Expression<Func<TObject, bool>> predicate);
    TObject Find(params object[] keys);
    TObject Find(Expression<Func<TObject, bool>> predicate);
    TObject Create(TObject t);
    int Delete(TObject t);
    int Delete(Expression<Func<TObject, bool>> predicate);
    int Update(TObject t);
    void Ignore(TObject t);

    int Count { get; }
}

Generic BaseRepository

public class BaseRepository<TObject> : IRepository<TObject>
    where TObject : class
{
    protected AppDbContext Context = null;

    public BaseRepository(AppDbContext context)
    {
        Context = context;
    }

    protected DbSet<TObject> DbSet
    {
        get { return Context.Set<TObject>(); }
    }

    public virtual int Count
    {
        get { return Queryable.Count<TObject>(DbSet); }
    }

   // ... (You get the picture)
}

的UnitOfWork

public class UnitOfWork : IDisposable
{
    private readonly AppDbContext _context = new AppDbContext();

    private BaseRepository<Order> _orderRepository;
    private BaseRepository<Product> _productRepository;
    private BaseRepository<ApplicationUser> _userRepository;
    private bool _disposed;

    public BaseRepository<Order> OrderRepository
    {
        get
        {
            if (_orderRepository == null)
            {
                _orderRepository = new BaseRepository<Order>(_context);
            }
            return _orderRepository;
        }
    }

    public BaseRepository<Product> ProductRepository
    {
        get
        {
            if (_productRepository == null)
            {
                _productRepository = new BaseRepository<Product>(_context);
            }
            return _productRepository;
        }
    }

    public BaseRepository<ApplicationUser> UserRepository
    {
        get
        {
            if (_userRepository == null)
            {
                _userRepository = new BaseRepository<ApplicationUser>(_context);
            }
            return _userRepository;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }
}

现在 - 没有&#34;服务&#34;和新的n层 - 我在我的控制器中使用它。

 public class ProductController : Controller
{
    private UnitOfWork _unitOfWork = new UnitOfWork();

    // GET: /Product/
    [Route]
    public ActionResult Index()
    {
        var model = _unitOfWork.ProductRepository.All();
        return View(model);
    }

// Etc...

但是现在我将所有内容划分为单独的层次,我无法做到这一点。而且我不想让我的工作单元类来映射ViewModel。

这是我尝试创建这个&#34;服务&#34; (不确定它的名称是否正确):

ViewModelService

 public class ViewModelService : IViewModelService
 {
    private readonly UnitOfWork _unitOfWork = new UnitOfWork();

    public T GetSingle<T>(int key)
    {
        // Get appropriate repository based on T1?

        throw new System.NotImplementedException();
    }

    public IQueryable<T> GetAll<T>()
    {
        throw new System.NotImplementedException();
    }
}

现在我遇到了这个问题 - 如何确认我打电话时:

_viewModelService.GetSingle<ProductVM>(id);

它通过自身(通过反思?)来计算 - 它应该调用:

_unitOfWork.ProductRepository.Find(id)

在存储库内部?

哇,我觉得我做了一个糟糕的工作来解释这个! :)

TL; DR

我有一个 UnitOfWork 类:

 public class UnitOfWork : IDisposable
{
    private readonly DbContext _context = new DbContext();

    private BaseRepository<Order> _orderRepository;
    private BaseRepository<Product> _productRepository;
    private BaseRepository<ApplicationUser> _userRepository;
    private bool _disposed;

    public BaseRepository<Order> OrderRepository
    {
        get
        {
            if (_orderRepository == null)
            {
                _orderRepository = new BaseRepository<Order>(_context);
            }
            return _orderRepository;
        }
    }

    public BaseRepository<Product> ProductRepository
    {
        get
        {
            if (_productRepository == null)
            {
                _productRepository = new BaseRepository<Product>(_context);
            }
            return _productRepository;
        }
    }

    public BaseRepository<ApplicationUser> UserRepository
    {
        get
        {
            if (_userRepository == null)
            {
                _userRepository = new BaseRepository<ApplicationUser>(_context);
            }
            return _userRepository;
        }
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Save()
    {
        _context.SaveChanges();
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        _disposed = true;
    }
}

现在我想创建一个通用包装

public class ViewModelService : IViewModelService
{
    private readonly UnitOfWork _unitOfWork = new UnitOfWork();

    public T GetSingle<T>(int key)
    {
        // Get appropriate repository based on T1?

        throw new System.NotImplementedException();
    }
}

如何使用反射,以便在我要求GetSingle<ProductVM>(id)时,包装器会将其转换为对_unitOfWork.ProductRepository.Find(id);的调用 - 因此包装器知道调用正确UoW内的存储库。

呼。

2 个答案:

答案 0 :(得分:0)

为什么不使用MEF? 打破你的UOW它将组成存储库 - 你也将受益,你将没有重复的

get
    {
        if (_productRepository == null)
        {
            _productRepository = new BaseRepository<Product>(_context);
        }
        return _productRepository;
    }

为每个导出项添加元数据,然后在

 public T GetSingle<T>(int key)
{
    // Get appropriate repository based on T1?

    throw new System.NotImplementedException();
}

您可以根据它公开的元数据获取正确的插件。 或者您可以将所有存储库添加到ServiceLoactor,以便您可以编写 而不是

_unitOfWork.ProductRepository.Find(id);

ServiceLocator.Current.GetInstance<T>().find(id)

答案 1 :(得分:0)

其中一种方法是使用通用抽象类,并让具体子类覆盖提供实际存储库的特定部分。这样,大多数代码都可以放在抽象类中,并且仍然可以精确地提供子类级别所需的代码。

 // two generic types
 // TDTO - view model type
 // TDomain - domain type
 public abstract class AbstractViewModelService<TDTO, TDomain> : IViewModelService
 {
     private UnitOfWork _uow { get; }        

     public AbstractViewModelService( UnitOfWork uow )
     {
         this._uow = uow;
     }

     public abstract IRepository<TDomain> Repository { get; }

     public TDTO GetSingle<TDTO>(int key)
     {
         // Get appropriate repository based on T1?
         // it is here ->

         return Mapper.DynamicMap<TDTO>( this.Repository.Find( key ) );
     }
 }

 public class UserViewModelService : AbstractViewModelService<UserDto, User> 
 {
     public override IRepository<User> Repository
     {
         get
         {
             return this._uow.UserRepository;
         }
     }
     ...
 }

 public class AccountViewModelService : AbstractViewModelService<AccountDto, Account> 
 {
     public override IRepository<Account> Repository
     {
         get
         {
             return this._uow.AccountRepository;
         }
     }
     ...
 }