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

And*_*ers 48 c# nhibernate queryover

我有这个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();
    }
Run Code Online (Sandbox Code Playgroud)

您提供自由文本搜索字符串和标签列表.问题是,如果邮件有多个标签,则会列出重复的时间.我想要一个基于Message实体的独特结果.我看了看

Projections.Distinct
Run Code Online (Sandbox Code Playgroud)

但它需要一个属性列表来处理不同的问题.这条消息是我的实体根,大部分是在不提供所有实体属性的情况下获得此行为的方法吗?

提前谢谢,安德斯

Sly*_*Sly 67

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

.SetResultTransformer(new DistinctEntityRootTransformer())
Run Code Online (Sandbox Code Playgroud)

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

.TransformUsing(Transformers.DistinctRootEntity)
Run Code Online (Sandbox Code Playgroud)

但请注意,这一切都发生在客户端,因此仍然会拉出所有重复的行.

  • 它不适用于分页.对于分页查询,您需要使用预测 (7认同)
  • ICriteria API与QUeryOver不是很流畅,但是.TransformUsing(Transformers.DistinctRootEntity); 工作完美. (5认同)
  • 这是否意味着您无法选择别名并执行不同的操作(因为它们都是变换器,您似乎只能使用一个变换器)? (2认同)
  • 我定期对这个问题进行投票,所以我有时会重新审视.今天没有更好的解决方案吗?在EF这只是有效.(他们还有其他问题) (2认同)

Cra*_*aig 27

尝试这样的事情

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);
}
Run Code Online (Sandbox Code Playgroud)

  • 工作,但......乏味.而不是As("xxx"),你可以调用WithAlias扩展方法来代替一些不那么神奇的字符串.谢谢 (6认同)

Chr*_*nes 13

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

tags.SelectList(t => t.SelectGroup(x => x.Id))
Run Code Online (Sandbox Code Playgroud)

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

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

tags.SelectList(t => t.SelectGroup(x => x.Id)
                      .SelectGroup(x => x.Name)
               )
Run Code Online (Sandbox Code Playgroud)