2016-07-24 2 views
1

Ich habe Domain-Modell folgende:Grails many-to-many - alle Objekte finden, die bestimmte Liste von Objekten enthalten

class Recipe { 
    String title 
    static hasMany = [ ingredients : Ingredient ] 
} 

class Ingredient { 
    String ingredient 
    static hasMany = [ recipes : Recipe ] 
    static belongsTo = Recipe 
} 

Grails die Tabelle Recipe_Ingredients mit dem Bestandteil ID und Rezept-ID erstellt.

Wie bekomme ich eine Liste von Rezepten mit einer Liste von Zutaten?

def egg = new Ingredient(ingredient:"Egg") 
def milk = new Ingredient(ingredient:"Milk") 
def flour = new Ingredient(ingredient:"Flour") 
def apple = new Ingredient(ingredient:"Apple") 
def banana = new Ingredient(ingredient:"Banana") 
def mango = new Ingredient(ingredient:"Mango") 


def pizza = new Recipe(title:"Pizza") 
pizza.addToIngredients(egg) 
pizza.addToIngredients(milk) 
pizza.addToIngredients(flour) 
pizza.save() 

def salad = new Recipe(title:"Fruit Salad with milk") 
salad.addToIngredients(apple) 
salad.addToIngredients(banana) 
salad.addToIngredients(mango) 
salad.addToIngredients(milk) 
salad.save() 

zum Beispiel:

[mango, milk] return me salad 
[milk] return me salad and pizza 
[milk, flour] return me pizza 
+0

aus Neugier, haben Sie 'Recipe.findAllByIngredientsInList ([Milch, Mango]) versucht' – injecteer

+0

OT, die "Pizza mit Ei und Milch" sein sollte;) – cfrick

Antwort

0

Hier müssen Sie, ob eine Reihe von ingredients zu überprüfen, die Zugehörigkeit zu einer Recipe eine Teilmenge der ingredients enthält, die Sie übergeben. Ich konnte mir keinen direkten Weg vorstellen mit GORM oder Criteira um dies zu tun. Es ist eine mögliche Hack dieser mit HQL:

public List<Recipe> fetchRecipe(List<String> ingredients){ 
    ingredients = ingredients.unique() 
    Recipe.executeQuery(''' 
     SELECT recipe FROM Recipe AS recipe 
     JOIN recipe.ingredients as ingredients 
     WHERE ingredients.ingredient in :ingredients 
     GROUP BY recipe 
     HAVING COUNT(recipe) = :count 
    ''', [ingredients: ingredients, count: ingredients.size().toLong()]) 
} 

Also, wenn Sie diese Methode ausführen mit:

println fetchRecipe(['milk'])*.title 
println fetchRecipe(['milk', 'banana'])*.title 
println fetchRecipe(['milk', 'egg'])*.title 

Es wird ausgegeben:

[Pizza, Fruit Salad with milk] 
[Fruit Salad with milk] 
[Pizza] 

So funktioniert es

  • Die Abfrage beginnt mit der Auswahl aller Rezepte, die einen der Zutaten in der Zutatenliste enthalten. Solange ein Rezept mindestens einen Bestandteil enthält, wird es zurückgegeben.

  • Dies erzeugt den Nebeneffekt der Auflistung eines Rezepts für jede passende Zutat, die es hat. Wenn ein Rezept beispielsweise zwei Zutaten enthält, wird das Rezept zweimal zurückgegeben. Die GROUP BY-Klausel bewirkt, dass die Abfrage diese doppelten Einträge herausfiltert.

  • Diese Duplikate sind jedoch der Schlüssel zu diesem Hack: Wenn die Liste der Zutaten ist eine eindeutige Liste, und Rezepte haben nicht die gleichen Zutaten mehr als einmal, dann hat das Rezept alle erforderlichen Zutaten, wenn die Anzahl der Duplikate entspricht der Anzahl der Zutaten. Und das macht die HAVING-Klausel, indem sie die Anzahl der Rezepte zählt.

+0

Oh .. perfekte Antwort. Vielen Dank. Ich komme, um Grails zu lernen und wusste nicht, wie ich es lösen sollte. Vielen Dank. –

Verwandte Themen