You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clean Architecture与DDD单库中复杂查询处理程序的实现位置疑问

Clean Architecture下复杂查询的处理方案

背景

我遵循Clean Architecture原则,将持久化实现细节隔离在Application Core之外:

  • 仓储接口位于Application Core项目中
  • Application Core项目不引用任何数据访问库(ORM)
  • Infrastructure项目引用ORM并实现仓储

遇到的困惑

在处理「获取包含客户详情及总价的逾期未结订单」这类查询时陷入两难:

  1. 该查询包含业务逻辑(订单判定为未结的条件、逾期的判定规则等)
  2. 需要性能优化(直接计算订单项总价,而非获取所有订单项)
  3. 已将OpenOrdersQuery DTO置于Application Core层,但不确定查询处理程序的放置位置:放在Infrastructure会把业务逻辑混入其中;放在Application Core则无法直接进行数据访问。

解决方案

核心思路是分离查询的业务规则与数据访问实现,具体步骤如下:

1. 在Application Core定义查询契约与业务规则

  • 将查询的业务判定逻辑封装为独立的规则类,比如OrderIsOpenSpecification、OrderIsOverdueSpecification,明确未结、逾期的业务标准,确保业务逻辑完全留在Application Core。
  • 定义查询处理接口,比如IQueryHandler<OpenOrdersQuery, IEnumerable<OpenOrdersResult>>,仅声明输入输出,不涉及任何数据访问细节。

2. 在Infrastructure实现查询处理程序

  • 实现Application Core中定义的查询处理接口,这里可以直接使用ORM进行性能优化(比如用LINQ直接计算订单项总价、关联客户表)。
  • 在处理程序中,调用Application Core的业务规则类过滤订单,保证业务逻辑不会混入数据访问代码中。

3. 通过依赖注入解耦

在应用启动时注册Infrastructure中的查询处理实现,让Application Core通过接口调用,无需关心具体的数据访问细节。

代码示例

Application Core 层

// 查询DTO
public class OpenOrdersQuery { }

// 查询结果DTO
public class OpenOrdersResult
{
    public Guid OrderId { get; set; }
    public string CustomerName { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime OrderDate { get; set; }
}

// 查询处理接口
public interface IQueryHandler<TQuery, TResult>
{
    Task<IEnumerable<TResult>> Handle(TQuery query);
}

// 业务规则:未结订单判定
public class OrderIsOpenSpecification
{
    public bool IsSatisfiedBy(Order order)
    {
        // 业务规则示例:订单状态为待支付且未取消
        return order.Status == OrderStatus.Pending && !order.IsCancelled;
    }
}

// 业务规则:逾期订单判定
public class OrderIsOverdueSpecification
{
    public bool IsSatisfiedBy(Order order)
    {
        // 业务规则示例:订单超过付款期限7天
        return DateTime.Now > order.PaymentDueDate.AddDays(7);
    }
}

Infrastructure 层

public class OpenOrdersQueryHandler : IQueryHandler<OpenOrdersQuery, IEnumerable<OpenOrdersResult>>
{
    private readonly AppDbContext _dbContext;
    private readonly OrderIsOpenSpecification _openSpec;
    private readonly OrderIsOverdueSpecification _overdueSpec;

    public OpenOrdersQueryHandler(AppDbContext dbContext, OrderIsOpenSpecification openSpec, OrderIsOverdueSpecification overdueSpec)
    {
        _dbContext = dbContext;
        _openSpec = openSpec;
        _overdueSpec = overdueSpec;
    }

    public async Task<IEnumerable<OpenOrdersResult>> Handle(OpenOrdersQuery query)
    {
        // 利用ORM实现性能优化的查询,同时应用业务规则过滤
        return await _dbContext.Orders
            .Where(o => _openSpec.IsSatisfiedBy(o) && _overdueSpec.IsSatisfiedBy(o))
            .Join(_dbContext.Customers, o => o.CustomerId, c => c.Id, (o, c) => new
            {
                o.Id,
                c.Name,
                Total = o.OrderItems.Sum(oi => oi.Quantity * oi.UnitPrice),
                o.OrderDate
            })
            .Select(result => new OpenOrdersResult
            {
                OrderId = result.Id,
                CustomerName = result.Name,
                TotalAmount = result.Total,
                OrderDate = result.OrderDate
            })
            .ToListAsync();
    }
}

这种方式既保证了业务逻辑的内聚性(留在Application Core),又让Infrastructure专注于高效的数据访问实现,完全符合Clean Architecture的隔离原则。

内容的提问来源于stack exchange,提问作者Liero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:55:39