web-dev-qa-db-ja.com

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

フリーテキスト検索文字列とタグのリストを指定します。問題は、メッセージに複数のタグがある場合、重複してリストされることです。メッセージエンティティに基づいた明確な結果が必要です。見たことがあります

Projections.Distinct

ただし、個別の質問に対するプロパティのリストが必要です。このメッセージは私のエンティティルートです。ほとんどの場合、すべてのエンティティプロパティを指定せずにこの動作を取得できますか?

事前に感謝、アンダース

48
Anders

ICriteria APIを使用している場合、以下が必要です。

.SetResultTransformer(new DistinctEntityRootTransformer())

QueryOver APIを使用している場合、次のものが必要です。

.TransformUsing(Transformers.DistinctRootEntity)

ただし、これはすべてクライアント側で発生するため、重複する行はすべてプルされます。

67
Sly

このようなものを試してください

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

SelectListとGroupByを使用できます。例:

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

機能し、同じクエリプランを個別に作成する必要があります。

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

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

私は最近、マップされたオブジェクトタイプに基づいて選択を適用するメソッドを作成しました。これをIQueryOverオブジェクト(クラスのプロパティ)に適用します。メソッドは、nhibernate構成にもアクセスできます。これらをメソッドパラメータとして追加できます。本番環境で作業する必要がありますが、メソッドはdevでうまく機能しており、これまでのところ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]));
        }
1
longday