【问题标题】:HQL query results "cannot be used in this generic collection" when returning a subclass返回子类时,HQL 查询结果“不能在此泛型集合中使用”
【发布时间】:2025-11-24 18:50:02
【问题描述】:

鉴于以下情况:

一个公司有一个产品对象的集合。
一个 Area 有一个 Product 对象的集合。
任何给定的产品都有一个公司和一个区域。
SpecialProduct 是 Product 的子类。

我在 NHibernate 中使用以下 HQL 查询。

// return all SpecialProperty objects for a given company and area.
IQuery query = session.CreateQuery("select product from Company as company " +
    "join company.Products as product " +
    "join product.Area as area " +
    "where company.Id = :coId " +
    "and area.Id = :arId " +
    "and product.class = MyNamespace.DomainModel.SpecialProduct ")
    .SetInt64("coId", companyId)
    .SetInt64("arId", areaId);
IList<SpecialProduct> specialProducts = query.List<SpecialProduct>();

执行上面的第二条语句时,我收到一条错误消息:

无法执行查询[SQL:SQL 不可用] 值“SpecialProduct”不是“MyNamespace.DomainModel.SpecialProduct”类型,不能在此通用集合中使用。
参数名称:值

(请注意,由于 SpecialProduct 类中的 ToString() 覆盖,对象在上面的消息中显示为“SpecialProduct”。)

如果我更改语句以返回超类 Product 的列表,就像这样......

IList<Product> products = query.List<Product>();  

...然后我没有收到错误,并且列表中返回了一个匹配的对象。在调试器中检查这个对象,我发现它实际上是一个根据 ToString() 覆盖的 SpecialProduct,但仔细观察我发现它是一个 NHibernate 代理类。如果我尝试将对象转换为 SpecialProduct,则转换失败。嗯……

我还检查了数据库本身并确认该记录已保存为 SpecialProduct(基于 join-subclass 表中存在匹配记录的事实)。

我需要将结果作为 SpecialProperty 对象的通用集合。

关于为什么这不起作用的任何想法?

【问题讨论】:

  • 问题突然消失了。由于代码中其他地方的一些更改(查询没有更改),查询现在返回类的实际实例,而不是类的 NHibernate 代理。去想...如果再次发生这种情况,知道为什么它开始返回实际对象而不是代理会很高兴。 :-S

标签: nhibernate hql


【解决方案1】:

这是设计使然。 NH 代理继承自基类型,而不是子类。

希望this link 会有所帮助。

【讨论】:

  • 感谢您的链接,迭戈。使用引用基类型的属性从另一个对象遍历到达的代理不能直接转换为子类型,这是有道理的。然而,在我的情况下,引用是 within 一个 HQL 查询,它也限制了返回类型(“...product.class= subtype”)。换句话说,我给了 NH 足够的信息,让它提前知道应该返回的类型。此外,我要求作为查询结果的子类型列表(而不是引用它们的对象列表)。有没有办法指示 NH 返回子类型?
  • 也许使用 CreateCriteria 代替?可能是session.CreateCriteria(typeof(SpecialProperty)....List&lt;SpecialProperty&gt;(); 之类的东西?
  • @MylesRip:没有。最好的情况是,它会有时(曾经在那里)工作,一旦你在会话中加载了该实例的代理,它就会惨遭破坏。
  • 那太糟糕了。我希望找到一个可以在 NHibernate 查询时应用的解决方案。我想我唯一的方法是根据需要使用“后门”(如您上面的链接中所述)。感谢您的帮助!