NHibernate:一对多联接时过滤结果

时间:2020-10-22 18:26:32

标签: c# nhibernate queryover

我试图根据左联接上所有对象的值来过滤查询。我的对象是这样定义的:

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。 我本以为可以反向搜索,在“成分表”中搜索具有正确成分和数量的所有记录,但是随后我想出了所有包含这些成分以及其他成分的食谱。 可以使用SQL查询来完成此操作吗?还是我必须接受这样的事实,即必须拔出所有记录(使用最少的过滤),然后在代码中对其进行过滤?

(作为奖励,我将来还必须过滤相似的配方,因此配方中的金额几乎相等,因此金额<1.05refAmount和&金额> 0.95refAmount)

1 个答案:

答案 0 :(得分:0)

好的,所以我设法找到了一个很好的解决方案。我需要运行的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));
}

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

https://stackoverflow.com/a/24334034/5426336

https://stackoverflow.com/a/3556840/5426336