使用Fluent nHibernate通过属性对对象子集合进行处理

时间:2011-05-26 14:25:32

标签: c# .net fluent-nhibernate queryover

请原谅我的无知,我是nHibernate的新手,并且在尝试使用nHibernate查询过滤子集合时遇到了概念问题

我的对象模型包含两个实体User和Task设置如下

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

我的数据库有两个表'task'和'user',我已经填写了

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对象的单个用户对象,而我得到的是同一个任务对象的3个副本(task.Id = 3),所有这些都包含所有对象5各自馆藏中的任务。

我想要做的事实上是可能的还是我应该只是在查询任务实体?

我希望情况不是这样,因为能够只看到用户活动的任务而不必乱用手动过滤会很好。

2 个答案:

答案 0 :(得分:0)

首先,我想我会将其分解为两个查询。在制作主要细节时,获取用户实体可能更有意义,然后为用户获取任务......

我使用QueryOver.Of<T>()并不是很好,但这是使用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>()能做你想要的,因为断开连接的查询需要一个过滤器来正确地拉回子元素。

答案 1 :(得分:0)

您可以在.TransformUsing( Transformers.DistinctRootEntity)方法之前应用List()以仅获取1个用户对象。 之后你所看到的是向数据库发出另一个查询以获取该用户的任务列表(不过滤掉活动的任务),这就是延迟加载的含义。 在数据库配置部分添加.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();