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

DDD架构下优化Shop聚合根数据库查询的方案(C#/.NET/EF)

DDD架构下店铺列表查询优化方案

符合架构要求的优化方案是存在的,核心思路是在基础设施层实现针对性的投影查询,避免加载完整Shop实体,同时不修改领域层的IShopRepository接口,也不在领域层新增任何DTO类。以下是几种可行方案:


方案1:基础设施层新增查询方法返回值元组,应用层映射为ShopDto

步骤:

  1. 在基础设施层的ShopRepository实现类中,新增专门的查询方法,通过EF Core投影仅获取所需字段,返回值元组集合:
public async Task<IEnumerable<(Guid ShopId, string ShopName, Address ShopAddress)>> GetShopSummariesAsync()
{
    return await _dbContext.Shops
        .Select(s => (
            ShopId: s.Id.Value, // 假设ShopId值对象包含Value属性对应Guid
            ShopName: s.ShopName.Value, // ShopName值对象取实际字符串值
            ShopAddress: s.ShopAddress // 直接投影Address值对象
        ))
        .ToListAsync();
}
  1. 在应用层服务中,调用该方法并映射为ShopDto:
public async Task<IEnumerable<ShopDto>> GetShopListAsync()
{
    // 若依赖注入的是IShopRepository,可向下转型为具体实现类(或直接注入ShopRepository)
    var shopSummaries = await ((ShopRepository)_shopRepository).GetShopSummariesAsync();
    
    return shopSummaries.Select(s => new ShopDto
    {
        ShopId = s.ShopId,
        ShopName = s.ShopName,
        ShopAddress = s.ShopAddress
    });
}

方案2:应用层定义查询模型,基础设施层实现专用查询接口(更符合依赖倒置)

步骤:

  1. 在应用层定义仅用于查询的模型(不属于领域模型):
public record ShopSummary
{
    public Guid ShopId { get; init; }
    public string ShopName { get; init; }
    public Address ShopAddress { get; init; }
}
  1. 在应用层新增查询专用接口,避免污染领域层的IShopRepository:
public interface IShopQueryRepository
{
    Task<IEnumerable<ShopSummary>> GetShopSummariesAsync();
}
  1. 在基础设施层的ShopRepository中实现该接口,执行投影查询:
public class ShopRepository : IShopRepository, IShopQueryRepository
{
    private readonly AppDbContext _dbContext;

    // 原有的IShopRepository实现代码...

    public async Task<IEnumerable<ShopSummary>> GetShopSummariesAsync()
    {
        return await _dbContext.Shops
            .Select(s => new ShopSummary
            {
                ShopId = s.Id.Value,
                ShopName = s.ShopName.Value,
                ShopAddress = s.ShopAddress
            })
            .ToListAsync();
    }
}
  1. 在应用层服务中注入IShopQueryRepository,直接转换为ShopDto:
public async Task<IEnumerable<ShopDto>> GetShopListAsync()
{
    var shopSummaries = await _shopQueryRepository.GetShopSummariesAsync();
    return shopSummaries.Select(s => new ShopDto
    {
        ShopId = s.ShopId,
        ShopName = s.ShopName,
        ShopAddress = s.ShopAddress
    });
}

方案3:投影到匿名类型,应用层直接转换

这个方案无需额外定义结构,适合快速实现:
在基础设施层的ShopRepository中添加方法:

public async Task<IEnumerable<object>> GetShopBasicInfoAsync()
{
    return await _dbContext.Shops
        .Select(s => new
        {
            ShopId = s.Id.Value,
            ShopName = s.ShopName.Value,
            s.ShopAddress
        })
        .ToListAsync();
}

应用层中转换为ShopDto:

public async Task<IEnumerable<ShopDto>> GetShopListAsync()
{
    var basicInfos = await ((ShopRepository)_shopRepository).GetShopBasicInfoAsync();
    return basicInfos.Select(info => new ShopDto
    {
        ShopId = info.ShopId,
        ShopName = info.ShopName,
        ShopAddress = info.ShopAddress
    });
}

方案优势

  • 所有数据查询逻辑都封装在基础设施层,符合DDD职责划分
  • 领域层的IShopRepository接口完全无需修改,保持领域层纯粹性
  • 数据库仅查询所需的3个字段,减少数据传输和内存占用,显著提升性能
  • 未在领域层引入任何应用层依赖,完全符合架构约束

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:53:07