Критерий «многие ко многим» - PullRequest
1 голос
/ 10 декабря 2010

У меня есть список вопросов, каждый из которых связан со списком тегов.

И следующие данные:

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

Следующие критерии:

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

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

возвращает (я понимаю, почему, "in" действует как ИЛИ)

Question1, Question2, Question3, Question4

Или я хотел бы получить только

Question2, Question3

, так как они оба имеют tag1 И tag2.Есть ли способ сделать это?

В SQL я бы сделал что-то вроде:

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 
)

Ответы [ 2 ]

1 голос
/ 10 декабря 2010

Если у вас только два, используйте ограничение And

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

Если у вас более двух или неизвестное число, используйте Conjunction:

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>();

Существует также дизъюнкциякласс для обработки нескольких условий Or.

0 голосов
/ 13 декабря 2010

Использование 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);

И с использованием 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));
...