NHibernate如何实现含未映射列的子查询?
NHibernate硬编码关联字段实现子查询方案
完全可以通过硬编码关联字段的方式实现需求,不需要修改Order实体添加Client导航属性,下面提供两种常用实现方式:
1. HQL查询方式
直接在HQL中使用Order实体的ClientId属性(对应数据库外键字段)关联Client,通过子查询取首个Order的OrderProp字段:
SELECT c, (SELECT o.OrderProp FROM Order o WHERE o.ClientId = c.Id ORDER BY o.Id ASC LIMIT 1) AS FirstOrderProp FROM Client c
注:不同数据库的“取首个”语法略有差异,HQL会自动适配(比如SQL Server用
TOP 1,Oracle用ROWNUM = 1),只需保证Order实体中存在映射到fk_ClientId的ClientId属性即可。
如果Order实体未显式定义ClientId属性,也可以直接硬编码数据库外键字段名,用原生SQL片段实现:
SELECT c, (SELECT o.OrderProp FROM Order o WHERE o.fk_ClientId = c.Id ORDER BY o.Id ASC LIMIT 1) AS FirstOrderProp FROM Client c
2. Criteria API方式
使用DetachedCriteria构建子查询,通过属性或数据库字段硬编码关联条件:
基于Order实体属性的关联
假设Order实体已映射ClientId属性:
// 构建子查询:取当前Client的首个Order的OrderProp var subQuery = DetachedCriteria.For<Order>() .SetProjection(Projections.Property("OrderProp")) .Add(Restrictions.EqProperty("ClientId", "c.Id")) // 硬编码属性关联 .AddOrder(Order.Asc("Id")) // 按Id排序取首个 .SetMaxResults(1); // 主查询:查询Client并关联子查询结果 var clientQuery = session.CreateCriteria<Client>("c") .SetProjection(Projections.ProjectionList() .Add(Projections.Property("Id"), "ClientId") .Add(Projections.Property("Name"), "ClientName") .Add(Projections.Subquery(subQuery), "FirstOrderProp")) .SetResultTransformer(Transformers.AliasToBean<ClientWithFirstOrderDto>()); // 映射到DTO var result = clientQuery.List<ClientWithFirstOrderDto>();
直接硬编码数据库外键字段
如果Order实体没有ClientId属性,可通过SqlRestriction直接使用数据库外键字段fk_ClientId:
var subQuery = DetachedCriteria.For<Order>() .SetProjection(Projections.Property("OrderProp")) .Add(Restrictions.SqlRestriction("fk_ClientId = {alias}.Id")) // 硬编码数据库字段关联 .AddOrder(Order.Asc("Id")) .SetMaxResults(1); // 主查询写法同上,省略重复代码
关键注意点
- 只要数据库Order表存在
fk_ClientId外键,无论Order实体是否定义对应属性,都能通过硬编码字段实现关联 - 子查询中需指定排序规则(如按Id、创建时间)来明确“首个Order”的定义,避免结果不确定
内容的提问来源于stack exchange,提问作者Dario
相关产品推荐
相关产品推荐

