2009-05-08 13 views
7

Ich bin neu in NHibernate und ich versuche zu lernen, meine Daten abzufragen.Abfrage mit NHibernate

Unten ist die Konfiguration XML. Nur das Rezept wird angezeigt.

Ich möchte in der Lage sein, Rezepte nach Rezepttiteln aus eingegebenen Stichwörtern und auch Zutaten aus Zutatenname abzufragen.

So könnten Sie zum Beispiel "Pasta Wein" eingeben.

Dies ist, was ich versucht habe, aber gibt mir einen Fehler.

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%'"; 

Ich möchte die Sammlungen auch eifrig laden.

Werde ich nach rechts fragen ?? Ich muss in der Lage sein, die Abfragezeichenfolge aus meinen Suchkriterien zu erstellen. Das wäre in SQL einfach von mir.

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> 

Antwort

22

dynamische Abfragen zu erstellen, würde ich die Kriterien API verwenden. Dies macht die dynamische Abfrage sehr viel stabiler, da Sie keine String-Operationen benötigen, um sie aufzubauen.

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:

Für eifrig Laden Sie den Fetch-Modus einstellen könnten:

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

Aber ich würde diese nicht tun, weil Sie die Ergebnisse durch die multipliziert bekommen Anzahl der Bilder, Kommentare und Zutaten. Wenn Sie also 4 Bilder, 2 Kommentare und 12 Zutaten haben, erhalten Sie Ihr Rezept 96 Mal. Sie erkennen das nicht, weil NHibernate die Dinge wieder zusammenfügt, aber es generiert Verkehr zwischen der Anwendung und der Datenbank. Also lasst NHibernate es besser mit separaten Abfragen laden.


One mehr bearbeiten dynamische Abfrage Zusammensetzung zu zeigen.

// 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

Um dieses Problem zu lösen, können Sie den DistinctRootEntityResultTransformer erhalten –

+0

Warum würden Sie FetchMode.Join statt FetchMode.Eager für diese Lasten verwenden, wenn Sie wirklich beabsichtigten, die untergeordneten Objekte zu verwenden? –

+0

Ich sehe nicht, wie das dynamisch ist, wenn Sie die Schlüsselwörter fest codieren.Wie würdest du abfragen, wenn ich dir eine Reihe von Wörtern geben würde, die durch Leerzeichen getrennt sind ??? – Malcolm

1

Hier ist die oben genannten Kriterien mit dynamischen Keywords

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

Sowohl Stefan und Sathish der Beispiele verketten% Operatoren in die SQL. Dies ist nicht notwendig, da Restrictions.Like (nhib 2.0+) und Expression.Like (vor v2.0) 3 Parameterversionen mit einem MatchMode haben.

Volltextabfragen sind auch mit NHibernate Search verfügbar. Weitere Informationen finden Sie unter Ayende's example.