2010-12-10 4 views
1

Ich habe eine Liste von Fragen, die jeweils mit einer Liste von Tags verknüpft sind.NHibernate Viele-zu-viele-Kriterien

und die folgenden Daten:

Question1 : Tag1 
Question2 : Tag1, Tag2 
Question3 : Tag1, Tag2, Tag3 
Question4 : Tag1, Tag3 

die folgenden Kriterien:

var tagsIds = new int[] { tag1, tag2 }; 

var res = session.CreateCriteria<Question>() 
    .CreateCriteria("Tags") 
    .Add(Restrictions.In("id", tagsIds)) 
    .List<Question>(); 

gibt (Ich verstehe, warum die "in" wirkt wie ein OR) oder

Question1, Question2, Question3, Question4 

Ich möchte nur

bekommen

wie sie beide tag1 UND tag2 haben. Ich habe einen Weg, es zu tun?

In SQL, ich möchte etwas tun:

SELECT * 
FROM Question q 
WHERE EXISTS (
    SELECT * 
    FROM QuestionsToTags qtt 
    WHERE qtt.Question_id = q.Id 
    AND qtt.Tag_id IN (1, 2) 
    GROUP BY qtt.Question_id 
    HAVING COUNT(qtt.Question_id) >= 2 
) 

Antwort

0

Mit hql:

var q = NHibernateSession.CreateQuery(
@"from Question question 
    where exists( 
     select q.id from Question q 
     join q.Tags t 
     where 
      t.id in (:ids) 
      and q.id = question.id 
     group by q.id 
     having count(t.id)=:c_count)"); 

q.SetParameterList("ids", tagIds); 
q.SetInt32("c_count", tagIds.Length); 

Und mit einem ICriteria:

// here is the exists part 
var dCriteria = DetachedCriteria.For<Question>("q") 
    .SetProjection(Projections.GroupProperty(Projections.Id())) 
    .Add(Restrictions.Eq(Projections.Count(Projections.Id()), tagIds.Length)) 
    // here we filter on the "parent" criteria 
    .Add(Restrictions.EqProperty("q.id", "question.Id")) 
    .CreateCriteria("Tags") 
    .Add(Restrictions.In("id", tagIds)); 

var crit = NHibernateSession 
    .CreateCriteria<Question>("question") 
    .Add(Subqueries.Exists(dCriteria)); 
1

Wenn Sie nur zwei verwenden dann ein und Beschränkung

var res = session.CreateCriteria<Question>() 
    .CreateCriteria("Tags") 
    .Add(Restrictions.And(Restrictions.Eq("id", tag1), Restrictions.Eq("id", tag2)) 
    .List<Question>(); 

Wenn Sie mehr als zwei oder eine unbekannte Zahl haben dann Conjunction verwenden :

var conj = new Conjunction(); 
// use a loop to add all tags if number is unknown 
conj.Add(Restrictions.Eq("id", tag1); 
conj.Add(Restrictions.Eq("id", tag2); 

var res = session.CreateCriteria<Question>() 
    .CreateCriteria("Tags") 
    .Add(conj) 
    .List<Question>(); 

Es gibt auch eine Disjunktion Klasse mehr oder Bedingungen zu behandeln.

+0

Vielen Dank, aber dies nicht funktioniert, wie es die folgende SQL erzeugt: SELECT [snipped] FROM "Frage" this_ inner join QuestionsToTags tags3_ on this_.Id = tags3_.Question_id inner join "Tag" tag1_ on tags3_.Tag_id = tag1_.Id WHERE (tag1_.Id = 1 und tag1_.Id = 2). Also wird nichts zurückgegeben, da id nicht sowohl 1 als auch 2 sein kann – mathieu