将集合查询从SQL转换为nhibernate

将集合查询从SQL转换为nhibernate,sql,nhibernate,many-to-many,subquery,Sql,Nhibernate,Many To Many,Subquery,我有一个数据库模式,其中有一个Product、Category、CategoryFeature和一个ProductCategoryFeatureValue 使用Fluent NHibernate映射模型,但基本上如下所示 Product ------- ID Title Category -------- ID Title CategoryFeature --------------- ID CategoryID Title ProductCategoryFeatureValue ----

我有一个数据库模式,其中有一个Product、Category、CategoryFeature和一个ProductCategoryFeatureValue

使用Fluent NHibernate映射模型,但基本上如下所示

Product
-------
ID
Title

Category
--------
ID
Title

CategoryFeature
---------------
ID
CategoryID
Title

ProductCategoryFeatureValue
---------------
ID
ProductID
CategoryFeatureID
_______________________

Category [one] <-> [many] CategoryFeature
Product [many] <-> [many] ProductCategoryFeatureValue
我可以做的另一个问题是:

SELECT * FROM product WHERE 
((SELECT id FROM productcategoryfeaturevalue AS feature1 WHERE feature1.ItemGroupID = product.id AND feature1.categoryFeatureID = 643229 LIMIT 1) IS     NOT NULL)
AND 
((SELECT id FROM productcategoryfeaturevalue AS feature2 WHERE feature2.ItemGroupID = product.id AND feature2.categoryFeatureID = 667811 LIMIT 1) IS NOT NULL)
两者都经过测试,效果良好。然而,我似乎无法使用NHibernate复制它们。有什么想法吗


谢谢

从问题中无法100%确定您的映射是什么,但这可能接近您需要的映射

object[] featureIds = new object[2];

featureIds[0] = 643229;
featureIds[1] = 667811;

ICriteria criteria = base.CreateCriteria(typeof(Product));
criteria.CreateAlias("ProductCategoryFeatureValueList", 
"ProductCategoryFeatureValue", JoinType.InnerJoin);
criteria.CreateAlias("ProductCategoryFeatureValue.CategoryFeatureID", 
"CategoryFeature", JoinType.InnerJoin);

criteria.Add(Expression.In("CategoryFeature.ID", featureIds));
如果表达式.In不存在;在你可以做一个快速的循环添加之后,你就不能做你现在正在做的事情了

criteria.Add(Expression.Eq("CategoryFeature.ID", featureIds[i]));

从问题中无法100%确定您的映射是什么,但这可能接近您所需要的

object[] featureIds = new object[2];

featureIds[0] = 643229;
featureIds[1] = 667811;

ICriteria criteria = base.CreateCriteria(typeof(Product));
criteria.CreateAlias("ProductCategoryFeatureValueList", 
"ProductCategoryFeatureValue", JoinType.InnerJoin);
criteria.CreateAlias("ProductCategoryFeatureValue.CategoryFeatureID", 
"CategoryFeature", JoinType.InnerJoin);

criteria.Add(Expression.In("CategoryFeature.ID", featureIds));
如果表达式.In不存在;在你可以做一个快速的循环添加之后,你就不能做你现在正在做的事情了

criteria.Add(Expression.Eq("CategoryFeature.ID", featureIds[i]));

我相信您在SQL中需要类似的东西

Select *
from Products p
where p.id in (
   select fv.ProductId
   from ProductCategoryFeatureValue fv
   where fv.CategoryFeatureID in (643229,643230)
   group by fv.ProductId
   having count(*)=@NumberOfDistinctFeaturesSelected 
)
这将使您不必为用户选择的每个功能多次加入ProductCategoryFeatureValue表。至少你会得到一个更好的查询计划。如果不喜欢IN子句,也可以使用临时表

就将其转换为NHibernate而言,它不支持CriteriaAPI中的任何HAVING子句逻辑,但使用HQL支持它


我相信您在SQL中需要类似的东西

Select *
from Products p
where p.id in (
   select fv.ProductId
   from ProductCategoryFeatureValue fv
   where fv.CategoryFeatureID in (643229,643230)
   group by fv.ProductId
   having count(*)=@NumberOfDistinctFeaturesSelected 
)
这将使您不必为用户选择的每个功能多次加入ProductCategoryFeatureValue表。至少你会得到一个更好的查询计划。如果不喜欢IN子句,也可以使用临时表

就将其转换为NHibernate而言,它不支持CriteriaAPI中的任何HAVING子句逻辑,但使用HQL支持它


我认为您最大的问题是在联接上添加一个条件。我还没有尝试过,但一直期待着NH3+的功能,它可以让你添加一个标准加入


CreateAliasstring associationPath、string alias、JoinType JoinType、ICriterion withClause CreateCriteriastring associationPath、string alias、JoinType JoinType、ICriterion withClause我认为最大的问题是在联接上添加条件。我还没有尝试过,但一直期待着NH3+的功能,它可以让你添加一个标准加入



CreateAliasstring associationPath、string alias、JoinType JoinType、ICriterion withClause CreateCriteriastring associationPath、string alias、JoinType JoinType、ICriterion withClause这将有助于了解对象模型是如何定义和映射的,这也是驱动NHibernate SQL生成的原因。此外,您正在寻找哪种NHibernate查询方法?Linq?、HQL?、QueryOver?QueryOver或Criteria,最好不要使用任何魔法字符串。如果有帮助的话,我已经添加了上面的模型信息。确切地说,它的映射方式并不重要——不是它不工作或什么的,只是我不知道如何在任何NH风格的查询中表达SQL查询。这将有助于了解对象模型是如何定义和映射的,这是驱动NHibernate生成SQL的原因。另外,你在寻找什么NHibernate查询方法?Linq?、HQL?、QueryOver?QueryOver或Criteria,最好不要使用任何魔法字符串。如果有帮助的话,我已经添加了上面的模型信息。确切地说,它是如何映射的并不重要——不是它不工作或者什么的,只是我不知道如何在任何NH风格查询中表达SQL查询。我稍后会检查它,但我已经尝试过类似的方法,并且criteria.AddExpression.EqCategoryFeature.ID,FeatureId[I]将导致始终为false,因为一个ID永远不可能同时是两个值。啊,我刚刚用一些我比较熟悉但结构相似的表尝试了它,并且可以看到您的问题。我将与NHibernate玩一玩,然后再与您联系。这种类型的查询不会导致返回重复的产品行吗?我稍后会检查它,但我已经尝试了类似的方法,并且criteria.AddExpression.EqCategoryFeature.ID、featureId[I]将导致始终为false,因为一个ID永远不能同时为两个值。啊,我刚刚尝试了一些我比较熟悉的表格,但结构相似,可以看出您的问题。我将与NHibernate玩一玩,然后再与您联系。这种类型的查询不会导致返回重复的产品行吗?有什么方法可以像“组合”HQL和条件一样?由于这个条件,我不想为所有其他条件转储Criteria API。我已经设法通过HQL实现了这一点,尽管您的解决方案似乎更优雅,只需一个连接,而不是每个选择的功能一个连接。在我看来,这种类型的条件比它应该做的要复杂得多-我想这在查询中不是一种罕见的条件类型?有些事情很难用Criteria/QueryOver/LinqAPI来完成,在像这样的特殊情况下,我很乐意
重新执行HQL查询以解决手头的问题。关于这个查询,唯一复杂的事情是必须选择零件的所有特征。使用HQL版本,您可以保持最高效的SQL,并且仍然保持在NHibernate上下文中,而不必下拉到存储过程中。是的,我也不喜欢HQL的神奇字符串元素,但是如果你保持最小的使用量,我看不出有太多的缺点。我还应该指出,在你的SQL和其他解决方案中,你将从查询结果中生成笛卡尔积,并可能通过网络发送比你想要的更多的数据行到根据所选功能的数量和表中找到的合格产品的数量,情况会呈指数级恶化。是的,但是您知道是否有一种方法可以在HQL中只创建一个条件,而剩下的则使用Criteria API?不,对不起,我从未尝试过这样做。您可能能够查询查询的外部部分“从产品中选择*”,但子查询部分需要是HQL。如果您担心神奇的字符串,您可以随时进行一些基于表达式的反射来构建查询文本,这仍然会为您提供一些重构支持。有没有什么方法可以喜欢“组合”HQL和条件?由于这个条件,我不想为所有其他条件转储Criteria API。我已经设法通过HQL实现了这一点,尽管您的解决方案似乎更优雅,只需一个连接,而不是每个选择的功能一个连接。在我看来,这种类型的条件比它应该做的要复杂得多-我想在查询中这不是一种罕见的条件类型?有些事情很难用Criteria/QueryOver/LinqAPI来完成,在像这样的例外情况下,我很乐意使用HQL查询来解决手头的问题。关于这个查询,唯一复杂的事情是必须选择零件的所有特征。使用HQL版本,您可以保持最高效的SQL,并且仍然保持在NHibernate上下文中,而不必下拉到存储过程中。是的,我也不喜欢HQL的神奇字符串元素,但是如果你保持最小的使用量,我看不出有太多的缺点。我还应该指出,在你的SQL和其他解决方案中,你将从查询结果中生成笛卡尔积,并可能通过网络发送比你想要的更多的数据行到根据所选功能的数量和表中找到的合格产品的数量,情况会呈指数级恶化。是的,但是您知道是否有一种方法可以在HQL中只创建一个条件,而剩下的则使用Criteria API?不,对不起,我从未尝试过这样做。您可能能够查询查询的外部部分“从产品中选择*”,但子查询部分需要是HQL。如果你担心神奇的字符串,你总是可以做一些基于表达式的反射来构建查询的文本,这仍然会给你一些重构支持。可以用循环的方式来添加额外的连接,但我认为由于指数连接而不是使用HQL版本,这将导致性能下降。可能是这样的通过循环这样做可以添加额外的连接,但我认为由于指数连接而不是使用HQL版本,这将导致性能不足。