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

機能し、distinct と同じクエリ プランを生成する必要があります。

グループに複数のアイテムが必要な場合は、次のようにします。

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

私は最近、マップされたオブジェクト タイプに基づいて個別選択を適用するメソッドを作成しました。これを IQueryOver オブジェクト (クラスのプロパティ) に適用します。メソッドは、nhibernate 構成にもアクセスできます。これらをメソッド パラメータとして追加できます。本番環境で作業する必要がありますが、メソッドは開発でうまく機能しており、これまでに 1 つのエンティティに対してのみ使用されていました。

このメソッドが作成されたのは、サーバー レベルでデータをページングしようとしていて、個別の結果トランスフォーマーが機能しないためです。

オブジェクト コレクション (query.List()) を取得した後、オブジェクトをリロードして、1 つから複数の子オブジェクトを設定する必要がある場合があります。多対 1 のマッピングは、遅延ロード用にプロキシされます。

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

1対多の関係をロードするために使用したコード... 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 に答える