使用 Fluent nHibernate 通过属性过滤对象子集合

发布于 2024-11-09 18:08:08 字数 2068 浏览 3 评论 0原文

请原谅我的无知,我是 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);
    }
}

我的数据库有我已经填充了两个表“任务”和“用户”

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 个任务。

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

我希望情况并非如此,因为如果能够看到用户活动的任务而不必费力进行手动过滤,那就太好了。

Please excuse my ignorance, I am new to nHibernate and am having a conceptual problem trying to filtering an child collection with an nHibernate query

My object model contains two entities User and Task set up like this

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

My nHibernate mappings for these are as follows

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

My database has two tables 'task' and 'user' which I have filled thusly

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

What I am trying to do is run a query that returns a specific user with only the active tasks in its 'Tasks' collection

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

When I execture this query I expect to get back a single user object with 3 Task objects in its Tasks collection, instead what I get is 3 copies of the same task object (task.Id = 3) all of which have all 5 Tasks in their respective collections.

Is what I am trying to do actually possible or should I just be querying on the Task entity instead?

I hope this is not the case as it would be nice to be able to just see a users active tasks without having to messing around with manual filtering.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

终止放荡 2024-11-16 18:08:08

首先,我想我会把它分成两个查询。在制作主从细节时,获取用户实体,然后获取用户的任务可能更有意义...

我不太擅长使用 QueryOver.Of(),但这里有一种使用 session.QueryOver() 的方法:

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

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

我认为您也可以使用过滤器,但这听起来不像您想要做的。我认为 QueryOver.Of() 不能满足您的要求,因为断开连接的查询需要一个过滤器来正确拉回子元素。

First, I think I would break it up into two queries. In making a master-detail it might make more sense to get the user entities, then get the tasks for the users...

I'm not really good using QueryOver.Of<T>(), but here's one way to do it using 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);

I think you can use filters too, but it didn't sound like what you wanted to do. I don't think QueryOver.Of<T>() does what you want, because the disconnected query would need a filter to correctly pull back the child elements.

墨小沫ゞ 2024-11-16 18:08:08

您可以在 List() 方法之前应用 .TransformUsing( Transformers.DistinctRootEntity) 来仅获取 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();

You can apply .TransformUsing( Transformers.DistinctRootEntity) before List() method to get only 1 user object.
After that what you are seeing is issuing another query to the database to get the list of tasks of that user (without filtering the active ones) and this is the meaning of lazy loading.
Add .ShowSql().FormatSql() in your db config section to see what's happening.

Also you can add this property to your Task class

public virtual User User { set; get; }

To have queries like this: (what you want in the first place)

 var list = session.QueryOver<Task>()                                                        
                            .Fetch(t=>t.User).Eager
                            .Where(t => t.Active && t.User.Id==3)
                            .TransformUsing(Transformers.DistinctRootEntity)
                            .List();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文