简体   繁体   English

如何使用nHibernate和QueryOver API获得明显的结果?

[英]How to get a distinct result with nHibernate and QueryOver API?

I have this Repository method 我有这个Repository方法

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

You supply a free text search string and a list of Tags. 您提供自由文本搜索字符串和标签列表。 The problem is that if a message has more then one tag it is listed duplicated times. 问题是,如果邮件有多个标签,则会列出重复的时间。 I want a distinct result based on the Message entity. 我想要一个基于Message实体的独特结果。 I've looked at 我看了看

Projections.Distinct

But it requires a list of Properties to to the distinct question on. 但它需要一个属性列表来处理不同的问题。 This Message is my entity root there most be a way of getting this behaviour without supplying all of the entity properties? 这条消息是我的实体根,大多数是在没有提供所有实体属性的情况下获得此行为的方法吗?

Thanks in advance, Anders 提前谢谢,安德斯

If you're using the ICriteria API, you need: 如果您使用的是ICriteria API,则需要:

.SetResultTransformer(new DistinctEntityRootTransformer())

If you're using the QueryOver API, you need: 如果您使用的是QueryOver API,则需要:

.TransformUsing(Transformers.DistinctRootEntity)

But beware, this all occurs on client side, so all the duplicate rows are still pulled. 但请注意,这一切都发生在客户端,因此仍然会拉出所有重复的行。

Try something like this 尝试这样的事情

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

You can use SelectList and GroupBy, eg: 您可以使用SelectList和GroupBy,例如:

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

Should work and produce the same query plan as distinct. 应该工作并生成相同的查询计划。

If you need multiple items in the group, do something like: 如果您需要组中的多个项目,请执行以下操作:

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

I have recently created a method to apply select distinct based on a mapped object type. 我最近创建了一个基于映射对象类型应用select distinct的方法。 It applies this to an IQueryOver object (property of class). 它将此应用于IQueryOver对象(类的属性)。 Method also has access to the nhibernate config. 方法还可以访问nhibernate配置。 You could add these as method parameters. 您可以将这些添加为方法参数。 Needs work for production, but method is working great in dev, only used it for one entity so far. 需要为生产工作,但方法在开发中工作得很好,到目前为止只用于一个实体。

This method was created because I am trying to page my data at the server level and a distinct result transformer would not work. 创建此方法是因为我尝试在服务器级别分页我的数据,并且不同的结果转换器不起作用。

After you get your object collection (query.List()) you may have to reload the objects to populate one to many child objects. 获得对象集合(query.List())后,可能必须重新加载对象以填充一个到多个子对象。 Many to one mappings will be proxied for lazy loads. 多个到一个映射将代表延迟加载。

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

Code I used to load one to many relations... T is the entity type. 代码我用来加载一对多关系... T是实体类型。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM