c# - ¿Cómo obtener un resultado distinto con nHibernate y la API QueryOver?
(4)
Tengo este método de depósito
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 proporciona 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. He visto
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
Pruebe 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);
}
Puede usar SelectList y GroupBy, por ejemplo:
tags.SelectList(t => t.SelectGroup(x => x.Id))
Debería funcionar y producir el mismo plan de consulta como distinto.
Si necesita varios elementos en el grupo, haga algo como:
tags.SelectList(t => t.SelectGroup(x => x.Id)
.SelectGroup(x => x.Name)
)
Recientemente he creado un método para aplicar select distinct basado en un tipo de objeto mapeado. 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 fue creado porque estoy tratando de enviar mis datos a nivel de 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]));
}
Si está utilizando la API de 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.