0

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

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

这是所有设置的说明。有三个项目

  • 西北网
  • 西北商业
  • 西北数据访问

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

-- 西北网 --

// 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;
    }
}

-- 西北商业 --

//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
  • 当所有业务对象都存在一些共同的读取需求时会发生什么?

有什么建议么 ?

4

1 回答 1

0

我认为一般概念是拥有“命令”和“查询”,并且在其中您可以依赖存储库。

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

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

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

特别是要回答您的问题“当所有业务对象都存在一些共同的读取要求时会发生什么”:想象一下,我在那里的 Query 和 Command 类采用一些常见的“IRepository”依赖项而不是像我的示例那样的“DBContext”这就是您可以跨业务对象“共享”该常见读取需求的方式。

于 2013-03-25T11:47:04.467 回答