2011-01-06 20 views
44

que tienen este método Repositorio¿Cómo obtener un resultado distinto con nHibernate y QueryOver API?

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

Usted suministra una cadena de búsqueda de texto libre y una lista de etiquetas. El problema es que si un mensaje tiene más de una etiqueta, aparece duplicado. Quiero un resultado distinto basado en la entidad Mensaje. Miré

Projections.Distinct 

Pero requiere una lista de Propiedades para la pregunta específica en. Este mensaje es la raíz de mi entidad. ¿Hay una forma de obtener este comportamiento sin proporcionar todas las propiedades de la entidad?

Gracias de antemano, Anders

Respuesta

61

Si está utilizando la API ICriteria, necesita:

.SetResultTransformer(new DistinctEntityRootTransformer()) 

Si está utilizando la API QueryOver, necesita:

.TransformUsing(Transformers.DistinctRootEntity) 

Pero ten cuidado, todo esto ocurre en el lado del cliente, por lo que todas las filas duplicadas aún se extraen.

+5

La API de ICriteria no es muy fluida con QueryOver, pero .TransformUsing (Transformers.DistinctRootEntity); funciona perfecto – Anders

+0

.TransformUsing (Transformers.DistinctRootEntity) No funcionó en absoluto con Paging:/¿Alguna otra idea? – Anders

+7

No funcionará con paginación. Para las consultas de paginación necesitará usar las proyecciones – Sly

25

intentar algo como esto

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

Funciona pero ... tedioso. En lugar de As ("xxx") puede llamar al método de extensión WithAlias ​​en lugar de un poco menos de cadenas mágicas. Gracias – Sam

+0

Ejemplo de método de extensión de Alias: .WithAlias ​​((= = entity.PropertyName) – xhafan

10

Puede utilizar SelectList y GroupBy, por ejemplo:

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

deben trabajar y producir el mismo plan de consulta como algo distinto.

Si necesita varios elementos en el grupo, hacer algo como:

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

He creado recientemente un método para aplicar seleccione diferenciado basado en un tipo de objeto asignada. Aplica esto a un objeto IQueryOver (propiedad de clase). El método también tiene acceso a la configuración nhibernate. Puede agregar estos como parámetros de método. Necesita trabajo para producción, pero el método funciona muy bien en dev, solo lo usó para una entidad hasta el momento.

Este método se creó porque estoy tratando de colocar mis datos en el nivel del servidor y un transformador de resultados distinto no funcionaría.

Después de obtener su colección de objetos (query.List()) puede que tenga que volver a cargar los objetos para llenar uno a muchos objetos secundarios. Se correlacionarán muchas a una asignaciones para cargas perezosas.

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

Código que solía cargar de una a muchas relaciones ... T es el tipo de entidad.

for (int i = 0; i < resp.Data.Count; i++) 
     { 
      resp.Data[i] = session.Load<T>(GetInstanceIdValue(resp.Data[i])); 
     } 
Cuestiones relacionadas