如何获得与nHibernate和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(); } 

您提供一个免费的文本searchstring和一个标签列表。 问题是,如果一个消息有多个标签,它将被列出重复次数。 我想要一个基于消息实体的独特结果。 我看过了

 Projections.Distinct 

但是它需要一个属性列表来解决不同的问题。 这个消息是我的实体根目录最有办法得到这种行为,而不提供所有的实体属性?

在此先感谢,安德斯

如果您使用ICriteria API,则需要:

 .SetResultTransformer(new DistinctEntityRootTransformer()) 

如果您使用QueryOver API,则需要:

 .TransformUsing(Transformers.DistinctRootEntity) 

但要小心,这一切都发生在客户端,所以所有重复的行仍然被拉。

尝试这样的事情

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

你可以使用SelectList和GroupBy,例如:

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

应该工作并生成相同的查询计划。

如果您需要组中的多个项目,请执行以下操作:

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

我最近创build了一个基于映射的对象types来应用select不同的方法。 它将此应用于IQueryOver对象(类的属性)。 方法也可以访问nhibernateconfiguration。 您可以将这些添加为方法参数。 需要为生产工作,但方法在开发中工作很好,迄今为止只用于一个实体。

这个方法的创build是因为我试图在服务器级别分页我的数据,而一个不同的结果转换器不起作用。

获取对象集合(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是实体types。

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