2011-01-06 2 views
44

У меня есть этот метод RepositoryКак получить отличный результат с помощью API nHibernate и QueryOver?

public IList<Message> ListMessagesBy(string text, IList<Tag> tags, int pageIndex, out int count, out int pageSize) 
    { 
     pageSize = 10; 
     var likeString = string.Format("%{0}%", text); 
     var query = session.QueryOver<Message>() 
      .Where(Restrictions.On<Message>(m => m.Text).IsLike(likeString) || 
      Restrictions.On<Message>(m => m.Fullname).IsLike(likeString)); 

     if (tags.Count > 0) 
     { 
      var tagIds = tags.Select(t => t.Id).ToList(); 
      query 
       .JoinQueryOver<Tag>(m => m.Tags) 
       .WhereRestrictionOn(t => t.Id).IsInG(tagIds); 
     }    

     count = 0; 
     if(pageIndex < 0) 
     { 
      count = query.ToRowCountQuery().FutureValue<int>().Value; 
      pageIndex = 0; 
     } 
     return query.OrderBy(m => m.Created).Desc.Skip(pageIndex * pageSize).Take(pageSize).List(); 
    } 

Вы поставку бесплатный поиск текста строки и список тегов. Проблема в том, что если сообщение имеет более одного тега, оно отображается в дублированном времени. Я хочу получить отличный результат на основе объекта Message. Я посмотрел на

Projections.Distinct 

Но для этого требуется список свойств для отдельного вопроса. Это сообщение является моим корнем сущности, наиболее вероятно, способ получить это поведение без предоставления всех свойств сущности?

Спасибо заранее, Андерс

ответ

61

Если вы используете API ICriteria, вам необходимо:

.SetResultTransformer(new DistinctEntityRootTransformer()) 

Если вы используете QueryOver API, вам необходимо:

.TransformUsing(Transformers.DistinctRootEntity) 

Но будьте осторожны, все это происходит на стороне клиента, поэтому все повторяющиеся строки по-прежнему вытягиваются.

+5

API ICriteria не очень хорошо владеет QUEROver, но .TransformUsing (Transformers.DistinctRootEntity); работает отлично. – Anders

+0

.TransformUsing (Transformers.DistinctRootEntity) Не работает вообще с Paging:/Любые другие идеи? – Anders

+7

Он не будет работать с поисковым вызовом. Для запросов поискового вызова вам понадобятся Projections – Sly

25

Try что-то вроде этого

public IPagedList<Client> Find(int pageIndex, int pageSize) 
{ 
    Client clientAlias = null; 

    var query = Session.QueryOver<Client>(() => clientAlias) 

     .Select(
      Projections.Distinct(
       Projections.ProjectionList() 
        .Add(Projections.Property<Client>(x => x.Id).As("Id")) 
        .Add(Projections.Property<Client>(x => x.Name).As("Name")) 
        .Add(Projections.Property<Client>(x => x.Surname).As("Surname")) 
        .Add(Projections.Property<Client>(x => x.GivenName).As("GivenName")) 
        .Add(Projections.Property<Client>(x => x.EmailAddress).As("EmailAddress")) 
        .Add(Projections.Property<Client>(x => x.MobilePhone).As("MobilePhone")) 
      ) 
     ) 
     .TransformUsing(Transformers.AliasToBean<Client>()) 

     .OrderBy(() => clientAlias.Surname).Asc 
     .ThenBy(() => clientAlias.GivenName).Asc; 

    var count = query 
     .ToRowCountQuery() 
     .FutureValue<int>(); 

    return query 
     .Take(pageSize) 
     .Skip(Pagination.FirstResult(pageIndex, pageSize)) 
     .List<Client>() 
     .ToPagedList(pageIndex, pageSize, count.Value); 
} 
+6

Работает, но ... утомительно. Вместо As («xxx») вы можете вызвать метод расширения WithAlias ​​вместо этого для немного менее магических строк. Спасибо – Sam

+0

Пример использования метода расширения: .WithAlias ​​(() => entity.PropertyName) – xhafan

10

Вы можете использовать SelectList и GroupBy, например:

tags.SelectList(t => t.SelectGroup(x => x.Id)) 

Должно работать и производить тот же план запроса в отличие.

Если вам нужно несколько элементов в группе, сделать что-то вроде:

tags.SelectList(t => t.SelectGroup(x => x.Id) 
         .SelectGroup(x => x.Name) 
       ) 
0

Недавно я создал метод, чтобы применить выбор отчетливого на основе отображенного типа объекта. Он применяет это к объекту IQueryOver (свойство класса). Метод также имеет доступ к конфигурации nhibernate. Вы можете добавить их как параметры метода. Нужна работа для производства, но метод отлично работает в dev, только использовал его для одного объекта.

Этот метод был создан, потому что я пытаюсь разместить свои данные на уровне сервера, и отличный трансформатор результатов не будет работать.

После того, как вы получите коллекцию объектов (query.List()), вам может потребоваться перезагрузить объекты для заполнения одного из многих дочерних объектов. Множество к одному сопоставлению будет проксировано для ленивых нагрузок.

public void DistinctRootProjectionList<E>() 
    { 
     var classMapping = Context.Config.GetClassMapping(typeof(E)); 
     var propertyIterator = classMapping.UnjoinedPropertyIterator; 
     List<IProjection> projections = new List<IProjection>(); 
     ProjectionList list = Projections.ProjectionList(); 

     list.Add(Projections.Property(classMapping.IdentifierProperty.Name), classMapping.IdentifierProperty.Name); 

     foreach (var item in propertyIterator) 
     { 
      if (item.Value.IsSimpleValue || item.Value.Type.IsEntityType) 
      { 
       list.Add(Projections.Property(item.Name), item.Name); 
      } 
     } 
     query.UnderlyingCriteria.SetProjection(Projections.Distinct(list)); 
     query.TransformUsing(Transformers.AliasToBean<E>()); 
    } 

Код Я использовал для загрузки одного из многих отношений ... T - тип сущности.

for (int i = 0; i < resp.Data.Count; i++) 
     { 
      resp.Data[i] = session.Load<T>(GetInstanceIdValue(resp.Data[i])); 
     } 
Смежные вопросы