2009-05-08 5 views
7

Я новичок в NHibernate, и я пытаюсь узнать, как запросить мои данные.Запрос с NHibernate

Ниже приведена конфигурация xml. Отображается только рецепт.

Я хочу иметь возможность запрашивать рецепты по рецепту из введенных ключевых слов , а также ингредиенты из имени ингредиента.

Таким образом, вы можете ввести «макаронное вино», например.

Это то, что я пробовал, но дает мне ошибку.

hql = "from Recipe r " + 
    "left join r.Images " + 
    "inner join r.User " + 
    "inner join r.Ingredients i " + 
    "where i.IngredientName Like '%pasta%' OR i.IngredientName Like '%wine%' OR r.RecipeTitle Like '%pasta' OR r.RecipeTitle Like '%wine%'"; 

Я хочу также загрузить коллекцию.

Я собираюсь спросить правильно ?? Мне нужно построить строку запроса из моих критериев поиска. Это было бы легко сформировать меня в SQL.

Malcolm

<class name="Recipe" table="Recipes" xmlns="urn:nhibernate-mapping-2.2"> 
    <id name="RecipeID" type="Int32" column="RecipeID"> 
     <generator class="identity" /> 
    </id> 
    <property name="RecipeTitle" type="String"> 
     <column name="RecipeTitle" /> 
    </property> 
    <property name="Completed" type="Boolean"> 
     <column name="Completed" /> 
    </property> 
    <property name="ModifiedOn" type="DateTime"> 
     <column name="ModifiedOn" /> 
    </property> 
    <property name="Rating" type="Double"> 
     <column name="Rating" /> 
    </property> 
    <property name="PrepTime" type="Int32"> 
     <column name="PrepTime" /> 
    </property> 
    <property name="CookTime" type="Int32"> 
     <column name="CookTime" /> 
    </property> 
    <property name="Method" type="String"> 
     <column name="Method" /> 
    </property> 
    <bag name="Images" inverse="true" cascade="all"> 
     <key column="RecipeID" /> 
     <one-to-many class="OurRecipes.Domain.RecipeImage, OurRecipes.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </bag> 
    <many-to-one name="Category" column="CategoryID" /> 
    <bag name="Comments" inverse="true" cascade="all"> 
     <key column="RecipeID" /> 
     <one-to-many class="OurRecipes.Domain.Comment, OurRecipes.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </bag> 
    <many-to-one name="User" column="EnteredByID" /> 
    <bag name="Ingredients" inverse="true" cascade="all"> 
     <key column="RecipeID" /> 
     <one-to-many class="OurRecipes.Domain.Ingredient, OurRecipes.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
    </bag> 
    </class> 

ответ

22

Для создания динамических запросов, я хотел бы использовать критерии API. Это делает динамический запрос более стабильным, потому что вам не нужны строковые операции для его создания.

ICriteria query = Session.CreateCriteria(typeof(Recipe), "r") 
    .CreateCriteria("Ingredients", "i", JoinType.InnerJoin) 
    .Add(
    Expression.Disjunction() // OR 
     .Add(Expression.Like("i.IngredientName", "%pasta%")) 
     .Add(Expression.Like("i.IngredientName", "%wine%")) 
     .Add(Expression.Like("r.RecipeTitle", "%pasta%")) 
     .Add(Expression.Like("r.RecipeTitle", "%wine%"))); 

List<Recipe> result = query.List<Recipe>(); 

Edit:

Для нетерпеливого загрузки вы можете установить выборки режима:

ICriteria query = Session.CreateCriteria(typeof(Recipe), "r") 
    .SetFetchMode("Images", FetchMode.Join) 
    .SetFetchMode("Comments", FetchMode.Join) 
    .SetFetchMode("Ingredients", FetchMode.Join) 

Но я бы не сделать это, потому что вы получите результаты, умноженные на количество изображений, комментариев и ингредиентов. Итак, если у вас есть 4 изображения, 2 комментария и 12 ингредиентов, вы получаете свой рецепт 96 раз. Вы этого не понимаете, потому что NHibernate снова объединяет все, но создает трафик между приложением и базой данных. Так что пусть NHibernate будет загружать его отдельными запросами.


еще один редактировать показать динамический состав запроса.

// filter arguments, all are optional and should be omitted if null 
List<string> keywords; 
TimeSpan? minCookingTime; 
TimeSpan? maxCookingTime; 
int? minRating; 
int? maxRating; 

ICriteria query = Session.CreateCriteria(typeof(Recipe), "r"); 

if (keyword != null) 
{ 
    // optional join 
    query.CreateCriteria("Ingredients", "i", JoinType.InnerJoin); 

    // add keyword search on ingredientName and RecipeTitle 
    var disjunction = Expression.Disjunction(); 
    foreach (string keyword in keywords) 
    { 
    string pattern = String.Format("%{0}%", keyword); 
    disjunction 
     .Add(Expression.Like("i.IngredientName", pattern)) 
     .Add(Expression.Like("r.RecipeTitle", pattern)); 
    } 
    query.Add(disjunction) 
} 

if (minCookingTime != null) 
{ 
    query.Add(Expression.Ge(r.CookingTime, minCookingTime.Value)); 
} 
if (maxCookingTime != null) 
{ 
    query.Add(Expression.Le(r.CookingTime, maxCookingTime.Value)); 
} 

if (minRating != null) 
{ 
    query.Add(Expression.Ge(r.Rating, minRating.Value)); 
} 
if (maxRating != null) 
{ 
    query.Add(Expression.Le(r.Rating, maxRating.Value)); 
} 
+0

Чтобы решить эту проблему, вы можете получить DistinctRootEntityResultTransformer –

+0

Зачем использовать FetchMode.Join вместо FetchMode.Eager для этих нагрузок, если вы действительно намеревались использовать дочерние объекты? –

+0

Я не вижу, как это динамично, когда вы жестко закодировали ключевые слова.Как бы вы запросили, если бы я дал вам строку слов, разделенных пробелами ??? – Malcolm

1

Вот вышеуказанные критерии с динамическими ключевыми словами

string searchQuery = "wine pasta"; 

ICriteria query = Session.CreateCriteria(typeof(Recipe), "r") 
        .CreateCriteria("Ingredients", "i", JoinType.InnerJoin) 
        .SetFetchMode("Images", FetchMode.Join) 
        .SetFetchMode("Comments", FetchMode.Join) 
        .SetFetchMode("Ingredients", FetchMode.Join) 
        .SetResultTransformer(new DistinctRootEntityResultTransformer()); 

var keywords = searchQuery.Split(' '); 

Disjunction keywordsCriteria = Restrictions.Disjunction(); 
foreach (var keyword in keywords) 
{ 
    keywordsCriteria.Add(Restrictions.Like("i.IngredientName", string.Format("%{0}%", keyword))); 
    keywordsCriteria.Add(Restrictions.Like("r.RecipeTitle", string.Format("%{0}%", keyword))); 
} 

query.Add(keywordsCriteria); 

List<Recipe> result = query.List<Recipe>(); 
5

Оба Стефана и примерами Sathish в конкатенацию% операторов в SQL. Это необязательно, поскольку Restrictions.Like (nhib 2.0+) и Expression.Like (до версии 2.0) имеют 3 версии параметров с MatchMode.

Disjunction keywordsCriteria = Restrictions.Disjunction(); 
foreach (var keyword in keywords) 
{ 
    keywordsCriteria.Add(Restrictions.Like("i.IngredientName", keyword, MatchMode.Anywhere)); 
    keywordsCriteria.Add(Restrictions.Like("r.RecipeTitle", keyword, MatchMode.Anywhere)); 
} 

Полные текстовые запросы также доступны в NHibernate Search. См. Ayende's example для более подробной информации.