我有一个表称为Recipes
包含每行一个配方。 我也有一个表称为RecipeIngredients
含有一种成分,所使用的由一个特定的食谱。 因此,每个Recipe
行有一个或更多的孩子RecipeIngredients
行。
我想要做的就是创建一个查询来查找包含所需成分的列表中的任何成分,所有配方。 例如,告诉我,请使用面粉,鸡蛋,香蕉或所有配方。
该SQL将是这个样子:
SELECT * FROM Recipes r
WHERE EXISTS (select 1 from RecipeIngredients where RecipeId = r.RecipeId and IngredientId = ANY (5, 10, 15) limit 1);
然而,我有一个艰难的时间搞清楚如何表达这种作为LINQ查询,或者使用.QueryOver<T>
方法。 我不想硬编码的SQL,因为这需要将数据库无关,我想配置NHibernate的方言,以生成正确的代码。
有任何想法吗?
NHibernate的有这个SQL语句,号称支持
- 15.8。 独立查询和子查询 ,
- 16.8。 子查询
语法是这样的:
var session = ...// get a ISession
Reciepe reciepe = null; // this will be a reference to parent
// the SELECT inside of EXISTS
var subquery = QueryOver.Of<ReciepeIngredient>()
// The PARENT handling here
// the filter, to find only related ingredients
.Where(item => item.ReciepeId == reciepe.ID)
.Where(Restrictions.In("ID", new[] { 5, 10, 15 }))
// Select clause
.Select(ing => ing.ID)
;
具有上述子查询,我们可以使用这样的
// the '() => reciepe' setting is essential here, it represents parent in a subquery
var query = session.QueryOver<Reciepe>(() => reciepe);
query.WithSubquery
// our EXISTS (...
.WhereExists(subquery);
var list = query
.List<Reciepe>();
注:让我们检查更加更深的子查询(IES)这里使用的查询上的hasMany参考
更多的一些细节:
拉迪姆的答案原来是表达子查询的最佳方式,但是有我花了一段时间才能弄清楚几个陷阱 。 因此,我会发布一个答案,以及填写详细信息。
首先,该行:
.Where(Restrictions.In("ID", new[] { 5, 10, 15 }))
如果没有实际的工作ID
是指实体本身。 换一种说法:
.Where(Restrictions.In("Ingredient", arrayOfIds))
将抛出一个非常混乱的空引用异常,因为成分字段映射到一个Ingredients
对象。 使用"IngredientId"
也不起作用。 在这种情况下,你必须使用这样的:
.Where(Restrictions.In("Ingredient", arrayOfIds
.Select(id => new Ingredients(id)).ToArray()))
到ID阵列投射到阵列Ingredients
对象。 在那之后,事情开始工作。
我还发现,进行的查询的运行速度noticably,至少在PostgreSQL的一个简单的性能改进。 如果您更改子查询:
WHERE存在(SELECT RecipeIngredientId FROM recipeingredients WHERE RecipeId = r.RecipeId和IngredientId在(:P0,:P1))
至:
WHERE存在(SELECT RecipeIngredientId FROM recipeingredients WHERE RecipeId = r.RecipeId和IngredientId在(:P0,:P1)LIMIT 1)
这将只需要嵌套查询中查询一行。 查询运行约两倍快给我。 这是很容易来表达:
var subquery = QueryOver.Of<RecipeIngredients>()
.Where(item => item.Recipe.RecipeId == recipe.RecipeId)
.Where(Restrictions.In("Ingredient", allowedIngs))
.Select(i => i.RecipeIngredientId).Take(1);
希望这可以帮助!
试试这个Linq查询:
recipes.Where(r => r.RecipeIngredients.Any(i => new long[]{5, 10, 15}.Contains(i.Id)));
文章来源: Is it possible to query all objects that have one or more possible children using NHibernate?