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

NHibernate查询指定嵌套属性映射失败求助

解决NHibernate QueryOver嵌套属性映射到实体的问题

嘿,我懂你碰到的麻烦了——你用Transformers.AliasToBean的时候,直接映射company_product.Company.Name这种嵌套属性会失败,这是因为默认的AliasToBean转换器不支持嵌套对象的属性赋值,它只能处理实体类的顶级属性,没法自动帮你实例化嵌套的Company或Product对象并设置它们的属性。

下面给你几个实用的解决方案:

方案1:使用AliasToBeanNestedResultTransformer(推荐)

NHibernate有一个扩展的结果转换器AliasToBeanNestedResultTransformer,专门用来处理嵌套属性的映射。你只需要替换原来的转换器即可:

Company_Product company_product = null;
Company company = null;
Product product = null;

IList<Company_Product> test = session.QueryOver<Company_Product>()
    .Left.JoinAlias(cp => cp.Company, () => company)
    .Left.JoinAlias(cp => cp.Product, () => product)
    .SelectList(list => list
        .Select(cp => cp.Company.Id).WithAlias(() => company_product.Company.Id)
        .Select(cp => cp.Company.Name).WithAlias(() => company_product.Company.Name)
        .Select(cp => cp.Product.Id).WithAlias(() => company_product.Product.Id)
        .Select(cp => cp.Product.Name).WithAlias(() => company_product.Product.Name)
        .Select(cp => cp.SalesDate).WithAlias(() => company_product.SalesDate)
    )
    // 替换成支持嵌套的结果转换器
    .TransformUsing(Transformers.AliasToBeanNested<Company_Product>())
    .List<Company_Product>();

注意:如果你的NHibernate版本较旧,可能需要确认项目已引用包含该转换器的扩展包,部分版本需要手动引入相关程序集。

方案2:手动构造实体对象

如果不想依赖扩展转换器,你可以直接在查询中获取所有需要的字段,手动创建并组装实体对象:

Company company = null;
Product product = null;

var test = session.QueryOver<Company_Product>()
    .Left.JoinAlias(cp => cp.Company, () => company)
    .Left.JoinAlias(cp => cp.Product, () => product)
    .SelectList(list => list
        .Select(cp => cp.Id)
        .Select(cp => cp.SalesDate)
        .Select(company => company.Id)
        .Select(company => company.Name)
        .Select(product => product.Id)
        .Select(product => product.Name)
    )
    .List<object[]>()
    .Select(arr => new Company_Product
    {
        Id = (int)arr[0],
        SalesDate = (DateTime)arr[1],
        Company = new Company
        {
            Id = (int)arr[2],
            Name = (string)arr[3]
        },
        Product = new Product
        {
            Id = (int)arr[4],
            Name = (string)arr[5]
        }
    })
    .ToList();

这种方式代码量稍大,但完全不需要额外依赖,逻辑清晰也好调试。

方案3:使用DTO中转

你可以先定义一个扁平化的DTO类,把所有需要的字段放在顶级,用AliasToBean映射到DTO后,再转换成实体类:

首先定义DTO:

public class CompanyProductDto
{
    public int Id { get; set; }
    public DateTime SalesDate { get; set; }
    public int CompanyId { get; set; }
    public string CompanyName { get; set; }
    public int ProductId { get; set; }
    public string ProductName { get; set; }
}

然后执行查询并转换:

CompanyProductDto dto = null;
Company company = null;
Product product = null;

var dtoList = session.QueryOver<Company_Product>()
    .Left.JoinAlias(cp => cp.Company, () => company)
    .Left.JoinAlias(cp => cp.Product, () => product)
    .SelectList(list => list
        .Select(cp => cp.Id).WithAlias(() => dto.Id)
        .Select(cp => cp.SalesDate).WithAlias(() => dto.SalesDate)
        .Select(company => company.Id).WithAlias(() => dto.CompanyId)
        .Select(company => company.Name).WithAlias(() => dto.CompanyName)
        .Select(product => product.Id).WithAlias(() => dto.ProductId)
        .Select(product => product.Name).WithAlias(() => dto.ProductName)
    )
    .TransformUsing(Transformers.AliasToBean<CompanyProductDto>())
    .List<CompanyProductDto>();

// 转换成目标实体类
var test = dtoList.Select(dto => new Company_Product
{
    Id = dto.Id,
    SalesDate = dto.SalesDate,
    Company = new Company { Id = dto.CompanyId, Name = dto.CompanyName },
    Product = new Product { Id = dto.ProductId, Name = dto.ProductName }
}).ToList();

这三种方案里,方案1最简洁,方案2最灵活,方案3适合复杂场景下的解耦,你可以根据自己的项目情况选择~

内容的提问来源于stack exchange,提问作者RYan.A

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:07:00