2015-09-17 5 views
0

У нас возникли проблемы с тем, как NHibernate (версия 4.0.0.4000 AND 4.0.4.4000 протестирована) возвращает duplicate. В приведенном ниже примере я получаю 566 результатов (правильный номер результатов), но только 549 являются уникальными, то есть имеется 17 дубликатов.NHibernate SetFirstResult приводит к дублирующим результатам

#region Get Record IDs 
public IList<string> GetRecordIds(string user, string agency, DateTime utcFrom, DateTime utcTo, SearchDateRangeType dateRangeType, IEnumerable<string> status, IEnumerable<string> billingStatus, IEnumerable<string> qaStatus, IEnumerable<string> transmissionStatus, IEnumerable<string> scheduledTransmissions, int pageSize = -1, int pageNumber = -1) 
{ 
    using (ISession session = NHibernateHelper.OpenSession()) 
    { 
     ICriteria crit = session.CreateCriteria<Metadata>(); 

     var dateDisjunction = Restrictions.Disjunction(); 

     dateDisjunction.Add(Restrictions.Between("IncidentDate", utcFrom, utcTo)); 

     crit.Add(dateDisjunction); 

     if (string.IsNullOrEmpty(agency) == false) 
     { 
      crit.CreateAlias("Ownership._entities.AsIList", "entities"); 
      crit.Add(Restrictions.Eq("entities._entityName._value", agency)); 
      crit.Add(Restrictions.Eq("entities._isDeleted._value", false) || Restrictions.IsNull("entities._isDeleted._value")); 
     } 

     crit.AddOrder(Order.Asc(Projections.Property("RecordId"))); 

     crit.SetProjection(Projections.Property("RecordId")); 

     if (pageSize > 0 && pageNumber > 0) 
     { 
      crit.SetFirstResult(pageSize * (pageNumber - 1)).SetMaxResults(pageSize); 
     } 

     var ret = crit.List<string>(); 

     return ret; 
    } 
} 
#endregion 

SQL Пример 1 является сгенерированным первого итерация кода из NHibernate. Последующие страницы (вторая страница вперед) используют ROW_NUMBER() OVER. SQL Sample 2 - это созданная вручную первая страница, которая использует ROW_NUMBER() OVER, как если бы это была следующая страница. NHibernate, по-видимому, «оптимизировал» прочь ROW_NUMBER() OVER для первой страницы, и это кажется (?) Причиной нашей проблемы.

SQL Пример 1: Сгенерировано NHibernate. Вызывает дубликаты.

SELECT 
    TOP (100) this_.RecordId as y0_ 
FROM 
    PcrMetadata this_ 
inner join 
    PcrEntities entities1_ 
     on this_.Id=entities1_.ListKey 
WHERE 
    (
     this_.IncidentDate between '0001-01-01 00:00:00.0000000' and '9999-01-01 00:00:00.0000000' 
    ) 
    and entities1_.Name = 'ClientIDNumber' 
    and (
     entities1_.Entities_IsDeleted = 0 
     or entities1_.Entities_IsDeleted is null 
    ) 

SQL Пример 2: Вручную создан на основе второй страницы NHibernate. Не вызывает дубликатов.

SELECT 
    TOP (100) this_.RecordId as y0_ 
FROM 
    (SELECT 
     this_.Record as y0_, 
     ROW_NUMBER() OVER(
    ORDER BY 
     CURRENT_TIMESTAMP) as __hibernate_sort_row 
    FROM 
     PcrMetadata this_ 
    inner join 
     PcrEntities entities1_ 
      on this_.Id=entities1_.ListKey 
    WHERE 
     (
      this_.IncidentDate between '0001-01-01 00:00:00.0000000' and '9999-01-01 00:00:00.0000000' 
     ) 
     and entities1_.Name = 'ClientIDNumber' 
     and (
      entities1_.Entities_IsDeleted = 0 
      or entities1_.Entities_IsDeleted is null 
     )) as query 
WHERE 
    query.__hibernate_sort_row > 0 -- CHANGE THIS NUMBER 

Я делаю что-то неправильно? Или что-нибудь, что я могу сделать, чтобы заставить NHibernate использовать ROW_NUMBER? Заранее благодарим за любую помощь!

ответ

1

Мы не можем ОБЪЕДИНЯТЬ коллекции и применять пейджинг. Потому что мы получаем cartesian product, который вызывается (опыт, описанный выше).

Решение, которое я предлагаю, - это (мой путь НИКОГДА) не присоединяется к коллекции. Чтобы получить аналогичные результаты, мы должны:

  • использования подзапросов применять WHERE
  • использование выборки пакетирования позже Получать все элементы коллекции без 1 + N выпуска

Существует detailed answer об этой проблеме.

Смотри также:

Существует больше о том, чтобы результат отличный, но это не может помочь здесь:

+0

Спасибо за ваш ответ! Просто я понимаю, есть ли проблема, даже если у Владения будет только одна запись, возвращенная из запроса? В обоих наборах сгенерированного SQL это конкретное имя, которое он ищет в Ownership, и в нашем приложении это будет одна строка. Я также проверил вручную SQL. – dythim

+0

В случае, если есть ровно один (но вы должны быть уверены, что можете гарантировать, что даже с помощью некоторых подпрограмм DB), вы можете присоединиться к коллекции, и ваш пейджинг будет работать. Но мой опыт - НИКОГДА не делай этого. это по понятию неверно. Да, это зависит от вас, но ... по крайней мере, попытайтесь подумать о моих предложениях. Я показал вам, как создавать коллекции FITLER и даже SELECT без 1 + N ...в то же время могу быть в состоянии перечислить несколько элементов-списков –

+0

Спасибо, я вижу, как то, что вы говорите, может быть проблемой, но я обеспокоен тем, что это не проблема, которую я вижу. Я вижу проблему с SQL, независимо от NHibernate. Два образца sql - это страница 0. NHibernate «оптимизировал» свою страницу 0 без 'ROW_NUMBER' - поэтому результат запроса должен быть таким же, как SQL-запрос с« ROW_NUMBER », но это не так. Имеет ли смысл моя логика? – dythim

 Смежные вопросы

  • Нет связанных вопросов^_^