nhibernate - получить счет, работающий с подзапросом - PullRequest
1 голос
/ 04 августа 2011

Так что у меня есть много-много отношений между чем-то, известным как Specialism и SpecialismCombo.То, что я пытаюсь сделать, это взять int [] из идентификаторов и проверить, есть ли уже комбо, содержащее специализации с этими идентификаторами.

Я был близок, но не совсем прав.Скажем, у меня есть специализации с идентификаторами 1 и 3, и я создаю комбо с этими специализациями.

Если я передам 3 и 1, то он возвращает ожидаемый комбо-идентификатор.

Если я передам 1затем он возвращает комбо-идентификатор с 1 и 3.

Я не могу просто полагаться на общее количество специализаций, связанных с комбо.Потому что, если у комбо есть два элемента, 1 и 4, и совпадающие элементы равны 1 и 3, я не хочу, чтобы это возвращалось как совмещенное комбо.

Так что мне нужно подсчитать эторезультат, и сопоставьте количество общих специализаций, связанных с комбо.Я не совсем понимаю, подхожу ли я подзапросу или критериям detatched, или как получить желаемый результат, используя критерии nhibernate.Спасибо за вашу помощь!

int[] SpecialismIds = ArrayExtensions.ConvertArray<int>(idCollection.Split(new char[] { '|' }));

    ICriteria query = m_SpecialismComboRepository.QueryAlias("sc");
        query.CreateAlias("sc.Specialisms", "s", NHibernate.SqlCommand.JoinType.InnerJoin);

    ICriterion lastCriteria = null;

    foreach(int i in SpecialismIds)
    {

         ICriterion currentCriteria = Restrictions.Eq("s.SpecialismId", i);
        if (lastCriteria != null)
                        lastCriteria = Restrictions.Or(lastCriteria, currentCriteria);
                    else
                        lastCriteria = currentCriteria;
    }

    if (lastCriteria != null)
                    query.Add(lastCriteria);

    IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");

    query.SetProjection(
        Projections.GroupProperty("sc.SpecialismComboId"),
        IdCount 
        );

    query.Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));

    var comboId = query.List();

Создается sql:

SELECT this_.SpecialismComboId as y0_, count(s1_.SpecialismId) as y1_ 
FROM dbo.SpecialismCombo this_ 
inner join SpecialismComboSpecialism specialism3_ on this_.SpecialismComboId=specialism3_.SpecialismId 
inner join dbo.Specialism s1_ on specialism3_.SpecialismComboId=s1_.SpecialismId WHERE s1_.SpecialismId = @p0 
GROUP BY this_.SpecialismComboId HAVING count(s1_.SpecialismId) = @p1',N'@p0 int,@p1 int',@p0=3,@p1=1

РЕДАКТИРОВАТЬ - Кажется, мне нужно либо что-то вроде ...

HAVING count (s1_.SpecialismId) = (выберите count (SpecialismId) из specialismComboSpecialism, где SpecialismComboId = y0 group by SpecialismComboId) == @ p2

Или, может быть, это проще, и мне нужно исключить SpecalismCombos, гдеcombo.specialisms не в коллекции идентификаторов.

Т.е.если в комбо есть специализации 1 и 3, но в коллекции только 1 .. тогда мы можем исключить это комбо, если 3 не находятся в коллекции ...

Редактировать 8/8/2011 ПошлиВернемся к тому, как получить нужный мне результат в SQL - и я считаю, что этот запрос работает.

WITH CustomQuery AS
        (
        SELECT sc.SpecialismComboId,
        count(s.SpecialismId) AS ItemCount
        FROM SpecialismCombo sc 
        inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
        inner join Specialism s on s.SpecialismId = scs.SpecialismId
        GROUP BY sc.SpecialismComboId 
        HAVING count(s.SpecialismId) = 2
        )

        SELECT CustomQuery.SpecialismComboId FROM CustomQuery
        INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
        WHERE scs.SpecialismId in (1,4)
        GROUP BY CustomQuery.SpecialismComboId 
        HAVING count(scs.SpecialismId) = 2

Итак, теперь мне просто нужно выяснить, как вызвать эту процедуру из моего кода nhibernate, передаваемого всоответствующие значения :)

Я также обнаружил в процессе, что мой класс отображения был неправильным - так как он помещал неправильные значения в таблицу отображения (т. е. specialismid заканчивался в поле specialismcomboid!)

Ответы [ 2 ]

0 голосов
/ 09 августа 2011

Итак, я закончил тем, что создал сохраненный процесс и использовал SQL CTE, чтобы получить только комбинации специализаций с правильным количеством специализаций.Сообщение об этом на случай, если кто-то еще столкнется с подобной проблемой.

Обнаружено заново после 8 месяцев использования nhibernate, что я забыл много вещей SQL :)

 DECLARE @IdCollectionCount         INT
    , @IdCollection             VARCHAR(250)
    , @CollectionDelimiter      NVARCHAR

    SET @IdCollectionCount = 2;
    SET @IdCollection = '1,4';
    SET @CollectionDelimiter= ',';

    WITH CustomQuery AS
        (
        SELECT sc.SpecialismComboId,
        count(s.SpecialismId) AS ItemCount
        FROM SpecialismCombo sc 
        inner join SpecialismComboSpecialism scs on sc.SpecialismComboId = scs.SpecialismComboId
        inner join Specialism s on s.SpecialismId = scs.SpecialismId
        GROUP BY sc.SpecialismComboId 
        HAVING count(s.SpecialismId) = @IdCollectionCount
        )

        SELECT Top 1 CustomQuery.SpecialismComboId FROM CustomQuery
        INNER JOIN SpecialismComboSpecialism scs on CustomQuery.SpecialismComboId = scs.SpecialismComboId
        INNER JOIN dbo.fn_SplitDelimited(@IdCollection,@CollectionDelimiter) AS ids
              ON scs.SpecialismId = CAST(ids.ListValue AS INT)
        GROUP BY CustomQuery.SpecialismComboId 
        HAVING count(scs.SpecialismId) = @IdCollectionCount
0 голосов
/ 04 августа 2011

Ваше решение на самом деле должно работать хорошо. Специализации фильтруются по id, и не должно быть ничего, что не ищется, поэтому count должен работать. Если только у вас к той же специализации не присоединился еще один раз. Этот currentCriteria lastCriteria материал выглядит немного странно, возможно, есть ошибка. Просто используйте Expression.In или Conjunction.

IProjection IdCount = Projections.Count("s.SpecialismId").As("IdCount");

IQuery query = session
  .CreateCriteria<SpecialismCombo>("sc")
  .CreateCriteria("Specialism", "s");

  .Add(Expression.In("s.SpecialismId", SpecialismIds));

  .SetProjection(
    Projections.GroupProperty("sc.SpecialismComboId"),
    IdCount);

  .Add(Restrictions.Eq(IdCount, SpecialismIds.Count()));

Должен привести к следующему запросу:

select ...
from 
  SpecialismCombo sc 
  inner join -- linktable ...
  inner join Specialism s on ...
where
  s.SpecialismId in (1, 4)
Group By sc.SpecialismComboId
having count(*) = 2

То же самое в HQL

from SpecialismCombo sc 
  join sc.Specialism s
where s.id in (:ids)
group by sc
having count(*) = :numberOfIds

Вы также можете присоединиться к специализации столько раз, сколько у вас есть идентификаторов:

IQuery query = session.CreateCriteria<SpecialismCombo>("sc")

int counter = 0;
foreach(int id in ids)
{
  string alias = "s" + counter++;
  query
    .CreateCriteria("Specialism", alias);
    .Add(Expression.Eq(alias + ".SpecialismId", id));
}

должен создать запрос, подобный этому:

select ...
from 
  SpecialismCombo sc 
  inner join -- linktable ...
  inner join Specialism s0 on ...
  inner join -- linktable ...
  inner join Specialism s1 on ...
where
  s0.SpecialismId = 1
  and s1.SpecialismId = 4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...