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

如何在领域层仓储接口中使用应用层DTO?(仓储模式)

问题描述

在学习ASP.NET整洁架构时,遇到以下问题:
应用层中有一个GetAllRestaurants查询,需要返回分页的餐厅对象。采用仓储模式,但领域层无法访问其他层,导致IRestaurantRepository中无法定义依赖应用层DTO或对象的方法。

应用层的Handle方法代码:

public async Task<PagedResult<List<RestaurantDto>>> Handle(GetRestaurantQuery request, CancellationToken cancellationToken)
{
    var restaurants = await _restaurantRepository.GetAllRestaurants(request);
    // etc...
}

领域层的IRestaurantRepository尝试使用应用层的GetRestaurantQuery,但因依赖问题无法运行:

using Domain.Entities;

namespace Domain.Repository
{
    public interface IRestaurantRepository
    {
        Task<PagedResult<List<Restaurant>>> GetAllRestaurants(GetRestaurantQuery query); // 此处报错,领域层无法访问应用层的GetRestaurantQuery
        Task<Restaurant> GetRestaurantById(int Id);
        Task<int> CreateRestaurant(Restaurant restaurant);
    }
}

考虑过两种方案:移除仓储层(但仍想了解正确处理方式);传递原始类型到IRestaurantRepository方法再在应用层构造对象,但觉得不合理。想知道正确的处理方式。

解决方案

根据整洁架构的核心依赖原则(领域层不依赖任何外层),可以采用以下几种合理的处理方式:

1. 在领域层定义查询参数模型

把分页、筛选等查询参数封装成领域层的纯数据模型,比如RestaurantQueryParams,这样领域层的仓储接口可以直接依赖这个模型,应用层的GetRestaurantQuery只需做简单映射即可:

// 领域层的参数模型
namespace Domain.Models
{
    public class RestaurantQueryParams
    {
        public int PageIndex { get; set; }
        public int PageSize { get; set; }
        // 其他筛选参数,如Name、Category等
    }
}

// 领域层的仓储接口修改为
public interface IRestaurantRepository
{
    Task<PagedResult<List<Restaurant>>> GetAllRestaurants(RestaurantQueryParams queryParams);
    // 其他方法...
}

// 应用层Handle方法中完成映射
public async Task<PagedResult<List<RestaurantDto>>> Handle(GetRestaurantQuery request, CancellationToken cancellationToken)
{
    var queryParams = new RestaurantQueryParams
    {
        PageIndex = request.PageIndex,
        PageSize = request.PageSize,
        // 映射其他筛选参数
    };
    var restaurants = await _restaurantRepository.GetAllRestaurants(queryParams);
    // 将领域实体Restaurant映射为应用层的RestaurantDto
}

这种方式完全符合整洁架构的依赖方向,既保持了参数的封装性,又避免了领域层对外层的依赖。

2. 直接传递离散原始参数(适合参数较少的场景)

如果查询参数数量不多,可以直接传递单个原始参数到仓储方法,避免额外的模型映射:

// 领域层仓储接口
public interface IRestaurantRepository
{
    Task<PagedResult<List<Restaurant>>> GetAllRestaurants(int pageIndex, int pageSize, string? nameFilter = null);
    // 其他方法...
}

// 应用层Handle方法调用
public async Task<PagedResult<List<RestaurantDto>>> Handle(GetRestaurantQuery request, CancellationToken cancellationToken)
{
    var restaurants = await _restaurantRepository.GetAllRestaurants(request.PageIndex, request.PageSize, request.NameFilter);
    // 后续DTO映射逻辑
}

这种方式简洁直接,但参数过多时会降低代码可读性和可维护性。

3. 定义通用分页参数基类

在领域层定义一个通用的PagedQueryParams基类,所有需要分页的查询参数都继承该基类,实现分页逻辑的复用:

// 领域层通用分页基类
namespace Domain.Models
{
    public class PagedQueryParams
    {
        public int PageIndex { get; set; } = 1;
        public int PageSize { get; set; } = 10;
    }

    // 餐厅查询参数继承基类,扩展筛选字段
    public class RestaurantQueryParams : PagedQueryParams
    {
        public string? Name { get; set; }
        public string? Category { get; set; }
    }
}

这种方式兼顾了复用性和封装性,适合存在多个分页查询场景的项目。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 20:38:19