1

無知で申し訳ありませんが、私は nHibernate を初めて使用し、nHibernate クエリで子コレクションをフィルタリングしようとして概念的な問題を抱えています。

私のオブジェクト モデルには、このように設定された User と Task の 2 つのエンティティが含まれています

public class User
{
    public User()
    {
        this.Tasks = new List<Task>();
    }

    public User(int id): this()
    {
        this.Id = id;
    }

    public virtual int Id { get; private set; }

    public virtual IList<Task> Tasks { get; set; }
}

public class Task
{
    public Task() { }

    public Task(int id, bool active): this()
    {
        this.Id = id;
        this.Active = active;
    }

    public virtual int Id { get; set; }

    public virtual bool Active { get; set; }
}

これらの nHibernate マッピングは次のとおりです。

public class UserMap: ClassMap<User>
{
    public UserMap()
    {
        Table("user");
        Id(x => x.Id);
        HasMany(x => x.Tasks);
    }
}

public class TaskMap : ClassMap<Task>
{
    public TaskMap()
    {
        Table("task");
        Id(x => x.Id);
        Map(x => x.Active);
    }
}

私のデータベースには、このように入力した「タスク」と「ユーザー」の2つのテーブルがあります

SELECT * FROM task;
+----+--------+---------+
| Id | Active | User_id |
+----+--------+---------+
|  1 |      1 |       3 |
|  2 |      1 |       3 |
|  3 |      1 |       3 |
|  4 |      0 |       3 |
|  5 |      0 |       3 |
|  6 |      1 |       1 |
|  7 |      1 |       1 |
|  8 |      1 |       1 |
|  9 |      0 |       1 |
| 10 |      0 |       1 |
+----+--------+---------+
10 rows in set

SELECT * FROM user;
+----+
| Id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
+----+
5 rows in set

私がやろうとしているのは、「タスク」コレクション内のアクティブなタスクのみを持つ特定のユーザーを返すクエリを実行することです

var query = QueryOver.Of<User>()
    .Where(u => u.Id == 3)
    .JoinQueryOver<Task>(x => x.Tasks)
    .Where(t => t.Active == true);

var results = dataProvider.ExcecuteQuery<User>(query);

このクエリを実行すると、Tasks コレクションに 3 つの Task オブジェクトを持つ単一のユーザー オブジェクトが返されると予想されますが、代わりに、同じタスク オブジェクト (task.Id = 3) の 3 つのコピーが返され、そのすべてに 5 つの Task がすべて含まれています。それぞれのコレクション。

私がやろうとしていることは実際に可能ですか、それとも代わりに Task エンティティでクエリを実行する必要がありますか?

手動のフィルタリングをいじる必要なく、ユーザーのアクティブなタスクを表示できると便利なので、そうではないことを願っています。

4

2 に答える 2

0

まず、2つのクエリに分割すると思います。マスターディテールを作成する際には、ユーザーエンティティを取得してから、ユーザーのタスクを取得する方が理にかなっている場合があります...

私は実際に使用するのは得意ではありませんがQueryOver.Of<T>()、これを使用してそれを行う1つの方法がありますsession.QueryOver<T>()

        var users = session.QueryOver<User>()
            .Where(u => u.Id == 3)
            .Fetch(o => o.Tasks)
            .Lazy()
            .SingleOrDefault();

        users.Tasks.TakeWhile(o => o.Active);

フィルターも使えると思いますが、やりたいとは思えませんでした。QueryOver.Of<T>()切断されたクエリには子要素を正しくプルバックするためのフィルターが必要になるため、私はあなたが望むことをしているとは思いません。

于 2011-05-26T17:51:22.883 に答える
0

.TransformUsing( Transformers.DistinctRootEntity)beforeメソッドを適用List()して、1つのユーザーオブジェクトのみを取得できます。その後、データベースに別のクエリを発行して、そのユーザーのタスクのリストを取得します(アクティブなタスクをフィルタリングせずに)。これが遅延読み込みの意味です。db configセクションを追加.ShowSql().FormatSql()して、何が起こっているかを確認します。

Taskまた、このプロパティをクラスに追加することもできます

public virtual User User { set; get; }

このようなクエリを作成するには:(そもそも必要なもの)

 var list = session.QueryOver<Task>()                                                        
                            .Fetch(t=>t.User).Eager
                            .Where(t => t.Active && t.User.Id==3)
                            .TransformUsing(Transformers.DistinctRootEntity)
                            .List();
于 2011-05-27T05:48:23.033 に答える