这是使用DI和存储库模式实现CQRS的方式吗?

时间:2013-01-28 10:46:25

标签: dependency-injection repository repository-pattern cqrs 3-tier

我将POC项目分配给了一个我要求实现命令查询分离,控制反转(具有依赖注入)和存储库模式的人。 “有人”给了我一个POC解决方案项目,但我不确定这是否就是这样做的。我将在此简要介绍POC项目

  • 该项目是一个简单的3层应用程序 - 表示层(PL),业务逻辑层(BLL)和数据访问层(DAL);每一层都是一个单独的项目
  • 表示层是一个Web应用程序,BLL和DAL是类库项目
  • 在业务层中,有定义的存储库接口。 BLL库的引用被添加到DAL项目中,在DAL项目中,有一些实现Repository Interfaces的具体类。这就是如何应用控制反转
  • 由于Command-Query-Separation已完成,因此Business Layer中的存储库接口仅声明Add / Update和Delete方法。对于读取,直接在DAL中有“读取”接口,在DAL中有实现这些接口的具体类。
  • 表示层包含对BLL库和DAL库的引用。通过BLL将呼叫添加/更新/删除路由到DAL,而任何读取都直接从DAL完成。我相信这符合Command-Query-Separation绕过BLL进行读取的概念。

以下是如何全部设置的说明。有三个项目

  • NW.Web
  • NW.Business
  • NW.DataAccess

以下是不同图层中代码的快照。

- NW.Web -

// A class in the Presentation Layer
public class CustomerPage 
{

    // Business layer Interface from  NW.Business namespace
    private ICustomerBusiness ICustB;

    //DAL Read interface from NW.DataAccess.Read namepsace
    private ICustomerRead<Guid> ICustR;

    //Constructor for the Customer Page that uses Constructor Injection
  public CustomerPage(ICustomerBusiness ICustB, ICustomerRead<Guid> ICustR)
    {
        this.ICustB = ICustB;
        this.ICustR = ICustR;
    }
}

- NW.Business -

//Declaration of business interface in the Business Layer
interface ICustomerBusiness
{
    void Persist();
}

// A class in the Business Layer that implements the business interface
public class Customer: ICustomerBusiness 
{
    //Repository interface object that will be injected by Constructor Injection.
    private ICustomerRepository ICustRep;

    public Customer(ICustomerRepository ICustRep)
    {
        this.ICustRep = ICustRep;
    }

    public void Persist()
    {

            ICustRep.AddOrUpdate();

    }
}

//Declaration of Repository interface in the Business Layer
public interface ICustomerRepository
{
    void AddOrUpdate();
    void Delete();
}

- NW.DataAccess -

public class CustomerRepository : ICustomerRepository
{

    public void AddOrUpdate()
    {
        //implementation of Add or Update
    }

    public void Delete()
    {
        //implementation of Delete
    }
}

//A Read interface in the Data Access Layer
interface ICustomerRead<T>
{
   // A read is returned as DTO since in Database this may map to more than 1 table
    CustomerDTO GetCustomerDetails(T id);
}

// An implementation of the Read Interface in the Data Access Layer
namespace NW.DataAccess.Read
{
    public class CustomerRead<T> : ICustomerRead<T> 
    {

        public CustomerDTO GetCustomerDetails(T id)
        {
           //implementation here
        }
    }
}

我的直觉是,这里有些不对劲。似乎CQRS或至少上述实现没有解决某些要求

  • 客户业务对象(客户类)可能需要从数据库中读取其内部用途(如初始化变量等)。使用直接在DAL层定义的读取,唯一的方法是在BLL中引用DAL dll。但这会产生循环引用并违背完成的IOC
  • 当所有业务对象都有一些常见的读取要求时会发生什么?

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

我认为一般的概念是拥有“命令”和“查询”,并且在那些内容中你可以依赖于存储库。

我实际上已经重构了一个ASP.NET MVC项目,其中每个Controller都依赖于一个或多个存储库来完成它的工作。当我重构它时,我为每个需要发生的特定操作创建了“Command”和“Query”对象,这大大简化了每个控制器。然后在那些命令和查询中,我使用现有的存储库来执行逻辑。

这似乎是额外的努力,但我这样做的原因是因为解决方案也有缓存。缓存代码很乱,有缓存键被添加到整个地方或从中删除。通过将所有数据访问分离为命令和查询,然后在访问或更新数据时引发域事件,可以简化和分离缓存管理代码。

有关如何实现简单命令/查询分离的概述,请参阅我最近关于该主题的博文,其中还包含示例代码和NuGet包,以帮助您更快地进行设置: http://www.nootn.com.au/2013/03/command-query-separation-to-better.html

特别要回答你的问题“当所有业务对象都有一些共同的读取要求时会发生什么”:想象一下,我在那里的Query和Command类采用了一些常见的“IRepository”依赖,而不是“DBContext”。我的例子就是这样,你就可以在业务对象之间“共享”这个常见的读取要求。