51

我有这个存储库方法

    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

但它需要一个属性列表来解决不同的问题。此消息是我的实体根,是否有一种方法可以在不提供所有实体属性的情况下获得此行为?

提前致谢, 安德斯

4

4 回答 4

68

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

.SetResultTransformer(new DistinctEntityRootTransformer())

如果您使用的是 QueryOver API,您需要:

.TransformUsing(Transformers.DistinctRootEntity)

但要注意,这一切都发生在客户端,所以仍然会拉出所有重复的行。

于 2011-01-06T14:58:07.233 回答
30

尝试这样的事情

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);
}
于 2011-02-24T00:33:32.890 回答
13

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

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

应该工作并产生相同的查询计划作为不同的。

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

tags.SelectList(t => t.SelectGroup(x => x.Id)
                      .SelectGroup(x => x.Name)
               )
于 2011-04-06T15:49:53.987 回答
2

我最近创建了一种基于映射对象类型应用 select distinct 的方法。它将它应用于 IQueryOver 对象(类的属性)。方法还可以访问 nhibernate 配置。您可以将这些添加为方法参数。需要为生产工作,但方法在开发中效果很好,到目前为止只用于一个实体。

创建此方法是因为我试图在服务器级别对我的数据进行分页,并且不同的结果转换器不起作用。

获得对象集合 (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]));
        }
于 2011-08-12T13:45:48.020 回答