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

仓储模式下如何仅筛选所需数据值?

解决方案:在分层架构中实现按需列查询(避免IQueryable暴露)

针对你提到的痛点——视图模型位于应用层、基础设施层不能直接依赖应用层,同时要实现仅查询构建视图模型所需的列,以下是几种实用的落地方案:

1. 共享契约层定义查询DTO

在领域层或专门的查询契约层(独立于应用/基础设施层)定义仅包含所需属性的DTO,作为两层之间的数据传输契约。基础设施层基于该DTO编写查询(仅选择需要的列),再返回给应用层,由应用层将DTO映射为视图模型。

示例代码:

契约层DTO

// 位于Domain/QueryContracts目录下
public class UserBasicInfoDto
{
    public Guid Id { get; set; }
    public string Username { get; set; }
    public string Email { get; set; }
}

基础设施层查询实现

public async Task<UserBasicInfoDto> GetUserBasicInfoAsync(Guid userId)
{
    return await _dbContext.Users
        .Where(u => u.Id == userId)
        .Select(u => new UserBasicInfoDto
        {
            Id = u.Id,
            Username = u.Username,
            Email = u.Email
        })
        .FirstOrDefaultAsync();
}

应用层映射为视图模型

var userDto = await _userRepository.GetUserBasicInfoAsync(userId);
var viewModel = new UserProfileViewModel
{
    UserId = userDto.Id,
    DisplayName = userDto.Username,
    ContactEmail = userDto.Email
};

2. 使用查询规范模式

应用层定义包含查询条件和属性选择逻辑的查询规范,基础设施层基于规范执行查询。这种方式通过表达式树传递选择逻辑,既隔离了层依赖,又能精准控制查询的列。

示例代码:

应用层查询规范

public class UserProfileSpecification : QuerySpecification<User, UserProfileViewModel>
{
    public UserProfileSpecification(Guid userId)
    {
        // 查询条件
        Criteria = u => u.Id == userId;
        // 投影到视图模型的逻辑
        Selector = u => new UserProfileViewModel
        {
            UserId = u.Id,
            DisplayName = u.Username,
            ContactEmail = u.Email
        };
    }
}

// 通用规范基类
public abstract class QuerySpecification<TEntity, TResult>
    where TEntity : class
{
    public Expression<Func<TEntity, bool>> Criteria { get; protected set; }
    public Expression<Func<TEntity, TResult>> Selector { get; protected set; }
}

基础设施层通用查询处理

public async Task<TResult> FindBySpecificationAsync<TEntity, TResult>(QuerySpecification<TEntity, TResult> spec)
    where TEntity : class
{
    return await _dbContext.Set<TEntity>()
        .Where(spec.Criteria)
        .Select(spec.Selector)
        .FirstOrDefaultAsync();
}

3. 借助AutoMapper的ProjectTo实现投影

如果项目使用AutoMapper,可以在应用层配置领域实体到视图模型的映射规则,基础设施层通过ProjectTo方法直接执行投影查询。这种方式通过泛型+IMapper接口实现解耦,避免基础设施层直接依赖应用层视图模型。

示例代码:

应用层映射配置

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<User, UserProfileViewModel>()
            .ForMember(dest => dest.UserId, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.DisplayName, opt => opt.MapFrom(src => src.Username))
            .ForMember(dest => dest.ContactEmail, opt => opt.MapFrom(src => src.Email));
    }
}

基础设施层通用投影查询

public async Task<TViewModel> GetProjectedAsync<TEntity, TViewModel>(Expression<Func<TEntity, bool>> criteria, IMapper mapper)
    where TEntity : class
{
    return await _dbContext.Set<TEntity>()
        .Where(criteria)
        .ProjectTo<TViewModel>(mapper.ConfigurationProvider)
        .FirstOrDefaultAsync();
}

应用层调用

var viewModel = await _userRepository.GetProjectedAsync<User, UserProfileViewModel>(
    u => u.Id == userId,
    _mapper
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:42:30