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

EF查询Attachment模型后如何映射为AttachmentResponse类集合?

问题描述

我有两个不同的类:
以下是名为"Attachments"的数据库表对应的模型:

namespace WebApi.Models
{
    public class Attachment
    {
        public enum EntityType
        {
            Transaction
        }
        public int AttachmentId { get; set; }
        public int EntityId { get; set; }
        public EntityType Type { get; set; }
        public string Filename { get; set; }
        public DateTime Created { get; set; }
        public DateTime Updated { get; set; }
    }
}

我的dbContext类如下:

namespace WebApi.Models
{
    public class accountingContext : DbContext
    {
        public DbSet<User>? Users { get; set; }
        public DbSet<Transaction>? Transactions { get; set; }
        public DbSet<Attachment>? Attachments { get; set; }

        ///...
    }
}

另外我有一个与Attachment模型类似的类,用于Web API请求的响应返回,代码如下:

namespace WebApi.Entities.AttachmentResponse;

public class AttachmentResponse
{
    public int AttachmentId { get; set; }
    public string Filename { get; set; }
}

出于某些原因,我希望将响应类与模型类分开,不使用模型类直接返回。在对模型类执行查询后,我需要将结果转换并映射到AttachmentResponse类。我尝试了以下代码:

List<WebApi.Entities.AttachmentResponse> attachments = (
    from a in db.Attachments
    from t in db.Transactions.Where(t => a.EntityId == t.TransactionId && t.UserId == userId)
    where a.EntityId == EntityId
    select new
    {
        a.AttachmentId,
        a.Filename
    }).ToList();

但上述尝试出现错误。我也查看过ConvertAll方法,但不知道如何在上述代码中使用。请问是否可以实现我想要的功能?如果可以,我的代码哪里出错了?


解决方案

完全可以实现你的需求,你的代码主要存在两个问题:

  1. 类型不匹配:查询中select new { ... }生成的是匿名类型,无法直接赋值给List<AttachmentResponse>,两者类型不兼容。
  2. 查询逻辑冗余且易出问题:where a.EntityId == EntityId和交叉连接Transactions的过滤条件重复,且这种写法会导致同一个Attachment对应多个Transaction时返回重复数据。

正确实现方式

方式一:直接在LINQ查询中构造AttachmentResponse

EF Core支持直接在查询中实例化DTO类(只要类有公开无参构造函数且属性可设置),这样查询会直接返回目标类型,无需额外转换:

List<WebApi.Entities.AttachmentResponse> attachments = (
    from a in db.Attachments
    where a.EntityId == EntityId 
          && db.Transactions.Any(t => t.TransactionId == a.EntityId && t.UserId == userId)
    select new WebApi.Entities.AttachmentResponse
    {
        AttachmentId = a.AttachmentId,
        Filename = a.Filename
    }).ToList();

这里用Any替代交叉连接,既保证了过滤逻辑,又避免了重复数据,同时直接构造目标类型实例,解决类型不匹配问题。

方式二:先查匿名类型再转换(适合复杂场景)

如果需要先处理匿名类型再转换,或者无法直接在查询中构造DTO,可以用Select或ConvertAll完成转换:

// 使用Select转换
List<WebApi.Entities.AttachmentResponse> attachments = (
    from a in db.Attachments
    where a.EntityId == EntityId 
          && db.Transactions.Any(t => t.TransactionId == a.EntityId && t.UserId == userId)
    select new
    {
        a.AttachmentId,
        a.Filename
    })
    .ToList()
    .Select(anon => new WebApi.Entities.AttachmentResponse
    {
        AttachmentId = anon.AttachmentId,
        Filename = anon.Filename
    })
    .ToList();

// 使用ConvertAll转换
List<WebApi.Entities.AttachmentResponse> attachments = (
    from a in db.Attachments
    where a.EntityId == EntityId 
          && db.Transactions.Any(t => t.TransactionId == a.EntityId && t.UserId == userId)
    select new
    {
        a.AttachmentId,
        a.Filename
    })
    .ToList()
    .ConvertAll(anon => new WebApi.Entities.AttachmentResponse
    {
        AttachmentId = anon.AttachmentId,
        Filename = anon.Filename
    });

注意:ConvertAll是List<T>的方法,必须先调用ToList()将查询结果加载到内存后才能使用。

额外提示

如果项目中有大量类似的DTO映射需求,建议使用AutoMapper这类映射库简化代码:

// 配置映射规则
var config = new MapperConfiguration(cfg => 
    cfg.CreateMap<Attachment, AttachmentResponse>()
       .ForMember(dest => dest.AttachmentId, opt => opt.MapFrom(src => src.AttachmentId))
       .ForMember(dest => dest.Filename, opt => opt.MapFrom(src => src.Filename)));

var mapper = config.CreateMapper();

// 查询并自动映射
List<AttachmentResponse> attachments = db.Attachments
    .Where(a => a.EntityId == EntityId && db.Transactions.Any(t => t.TransactionId == a.EntityId && t.UserId == userId))
    .ProjectTo<AttachmentResponse>(config)
    .ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 11:42:03