NHibernate:过滤一对多连接的结果

NHibernate: Filter result on one-to-many join

我正在尝试根据左侧联接中所有对象的值来过滤查询。我的对象定义如下:

public class Recipe
{
    public virtual long Id {get;set;}
    public virtual ISet<Ingredient> Ingredients { get; set; } = new HashSet<Ingredient>();
}

public class Ingredient
{
    public virtual long Id{get;set;}
    public virtual string Ingredient {get;set;}
    public virtual decimal Amount {get;set;}
}

它们是这样映射的:

<hibernate-mapping>
    <class name="Recipe"  table="Recipe">
        <set name="Ingredients" inverse="true">
            <key column="RecipeId" />
            <one-to-many class="Recipe" />
        </set>
    </class>
</hibernate-mapping>

<hibernate-mapping>
    <class name="Ingredient" dynamic-update="true" table="Ingredient" lazy="false">
        <id name="Id" column="Id" type="long" unsaved-value="0">
            <generator class="native" />
         </id>
        <property name="Ingredient" not-null="true" lazy="false"/>
        <property name= "Amount" column= "Amount" type="decimal" />    
    </class>
 </hibernate-mapping>

我想做的是能够根据成分搜索食谱。例如,假设我想找到成分为

的所有食谱
Ingredient | Amount
Sugar      |  100
Flour      |  200
Eggs       |    2

我什至不确定在 SQL 中我会怎么做。我试过这样的事情:

public Recipe FindRecipeByIngredients(ISet<Ingredient> ingredients)
{
    return this.Session.QueryOver<Recipe>()
            .Where(r => r.Ingredients.All(c => ingredients.Any(i => i.Ingredient == r.Ingredient && i.Amount == r.ConcentrAmountation))).SingleOrDefault();
}

但 Nhibernate 不知道如何将 All 转换为 SQL。 我在想也许可以反向搜索,在成分 table 中搜索具有正确成分和数量的所有记录,但随后我会想出包含这些成分和其他成分的所有食谱. 这可以使用 SQL 查询来完成,还是我必须接受这样一个事实,即我必须提取所有记录(使用最少的过滤)然后在代码中过滤它们?

(作为奖励,我还必须在未来过滤类似的食谱,因此数量几乎相等的食谱可能数量 <1.05refAmount && 数量 >0.95refAmount)

好的,所以我设法找到了一个相当好的解决方案。我需要 运行 的 sql 查询是:

    SELECT RecipeId
  FROM Ingredient
GROUP BY RecipeId 
HAVING SUM(CASE WHEN Ingredient = 'Ingredient1'  AND Amount = 200 THEN 1 ELSE 0 END) = 1
   AND SUM(CASE WHEN Ingredient = 'Ingredient2'  AND Amount = 300 THEN 1 ELSE 0 END) = 1
   AND ...

我在将它转换成 nhibernate 可以正确构造的东西时遇到了一些问题,结果是这样的:

ICriteria criteria = Session.CreateCriteria<Ingredients>()
                .SetProjection(Projections.GroupProperty(Projections.Property<Ingredient>(i => i.Recipe.Id)));

foreach (Ingredient ingredient in recipe.Ingredients)
{
    criteria.Add(
        Restrictions.Eq(
            Projections.Sum(
                Projections.Conditional(
                    Restrictions.Where<Ingredient>(i => i.Ingredient == ingredient.Ingredient && i.Amount == ingredient.Amount)
                    Projections.Constant(1),
                    Projections.Constant(0)
                 )
             ),
         1));
}

其中returns上面的查询。我尝试使用 Restrictions.Conjuntction 或使用 QueryOver 来执行此操作,但条件查询最终在 GROUP BY 之前的 WHERE 条件而不是 GROUP BY 之后的 HAVING 条件导致不正确的 sql 查询。这可能是 Nhibernate 中的一个错误(类似于 NH-2863),但我不确定。 如果有人找到更有效的方法来解决这个问题,我很乐意更新它。 答案也是基于 SO 上的这些答案: