如何在实体框架中查询相关实体(1:N关系)

发布于 2024-10-28 06:53:03 字数 925 浏览 1 评论 0原文

这样的场景中获取相关实体的更好方法是什么:{此处的类图}
我写了两种方式(另请注意类图中的差异)... Project 具有 ICollection of Tasks 属性,但 Member 没有。两种方法都有效,我想知道哪一种是正确的(更好/更快)。或者,如果没有一个是好的,那么在这些简单的场景中正确的方法是什么?
代码:

    using (var db = new EntitiesContext())
        {
            // way A
            Project project = db.Projects.Include("Tasks").First();
            List<Task> projectTasks = project.Tasks.ToList();
            count = projectTasks.Count;

            // way B
            Member member = db.Members.First();
            IQueryable<Task> memberTasks = from t in db.Tasks
                                           where t.AssignedTo.Id == member.Id
                                           select t;
            count = memberTasks.Count();
        }

我正在使用 EF 4.1 Code First。
顺便说一句:不要太担心结果(计数)。这只是一段测试代码,我当然想以后查询更多有用的信息。

What is a better way to get related entities in scenarios like this: {class diagram here}?
I wrote two ways (please also note the difference in class diagram)... Project has property with ICollection of Tasks, but Member doesn't. Both ways are working and I would like to know, which one is correct (better/faster). Or if none is good, then what is a correct way in these simple scenarios?
Code:

    using (var db = new EntitiesContext())
        {
            // way A
            Project project = db.Projects.Include("Tasks").First();
            List<Task> projectTasks = project.Tasks.ToList();
            count = projectTasks.Count;

            // way B
            Member member = db.Members.First();
            IQueryable<Task> memberTasks = from t in db.Tasks
                                           where t.AssignedTo.Id == member.Id
                                           select t;
            count = memberTasks.Count();
        }

I am using EF 4.1 Code First.
Btw: Don't worry about the result (getting count) too much. This is just a piece of test code, I would of course like to query more useful informations in future.

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

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

发布评论

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

评论(5

紫瑟鸿黎 2024-11-04 06:53:03

执行这些查询时,您的性能瓶颈通常属于以下两类之一:

  1. 获取太多不需要的数据。
  2. 与数据库的往返次数过多。

您的第一个示例可能会遇到第一个问题。如果您查看从数据库返回的数据,就会发现项目的所有数据都将针对与其连接的每个任务重复。如果您的项目有大量与之相关的数据,这可能会导致大量开销。如果是相当精简的话,就不会花那么多钱。

您的第二个示例创建第二个往返来获取任务。额外的往返会带来额外的开销,但这意味着总体上将返回更少的重复数据。一次额外的往返可能没什么大不了的,但如果您为多个项目执行此操作,则很容易导致数十次不必要的往返。

因此,根据您的数据通常是什么样子以及您真正想要从中得到什么,决定走哪条路实际上是一种平衡行为。在这种特殊情况下,您最好使用:

count = db.Tasks.Count(t => t.AssignedTo.Id == db.Members.FirstOrDefault().Id)

... 这将创建一个仅返回计数的优化查询,没有多余的数据或额外的往返。因此,您可以看到此类问题的答案实际上取决于您想要从数据库中获取的内容。

回复评论

如果您试图获取与某件事相关的所有任务,您的查询应该只获取任务。有很多方法可以做到这一点:

var memberTasks = db.Tasks.Where(t => t.AssignedTo.Id == memberId).ToList();

或(如果您还不知道成员的 ID):

var memberTasks = db.Tasks.Where(t => t.AssignedTo.[your criterion]))
                      .ToList();

或(如果您想同时为多个成员执行任务):

var tasksByMemberId = (from t in db.Tasks
                       where t.AssignedTo.[your criterion])
                       select new {MemberId = t.AssignedTo.Id, t})
                      .ToLookup(e => e.MemberId, e => e.t);

我可以继续。关键是所有这些查询都专门获取任务,而不用担心会员的数据。

添加额外的数据层也不应该改变太多事情:

var projectTasks = db.Tasks.Where(t => t.Iteration.Project.Id == projectId).ToList();

When performing these queries, your performance bottlenecks will generally fall under one of two categories:

  1. Getting too much data that you don't need.
  2. Making too many round-trips to the database.

Your first example may suffer from the first of these. If you look at the data that gets returned from the database, all the data for the Project will be repeated for every Task connected with it. If your Project has a lot of data associated with it, that can cause a lot of overhead. If it's fairly lean, it won't cost that much more.

Your second example creates a second round-trip to get the tasks. The additional round-trip introduces extra overhead, but it means that less duplicated data will be returned overall. A single extra round-trip probably isn't a big deal, but if you're doing this for multiple projects, you could easily end up with dozens of unnecessary round-trips.

So deciding which way to go will really be a balancing act, based on what your data typically looks like and what you really want from it. In this particular case, you'd be better off with:

count = db.Tasks.Count(t => t.AssignedTo.Id == db.Members.FirstOrDefault().Id)

... which will create a single optimized query that just returns the count, with no superfluous data or extra round-trips. So you can see how the answer to questions like this will really depend on what you're trying to get out of the database, exactly.

Reponse to Comment

If you're trying to get all the tasks related to something, your query should only be getting tasks. There are lots of ways to do this:

var memberTasks = db.Tasks.Where(t => t.AssignedTo.Id == memberId).ToList();

or (if you don't know the member's ID yet):

var memberTasks = db.Tasks.Where(t => t.AssignedTo.[your criterion]))
                      .ToList();

or (if you want the tasks for multiple members at once):

var tasksByMemberId = (from t in db.Tasks
                       where t.AssignedTo.[your criterion])
                       select new {MemberId = t.AssignedTo.Id, t})
                      .ToLookup(e => e.MemberId, e => e.t);

I could go on. The point is that all of these queries specifically get the Tasks out, without worrying the Member's data.

Adding an additional layer of data shouldn't change things much, either:

var projectTasks = db.Tasks.Where(t => t.Iteration.Project.Id == projectId).ToList();
探春 2024-11-04 06:53:03

方法 A 更干净,可以优化 SQL 查询,一次性提取所有相关数据。方法 B 类似于根据需要延迟加载相关数据。

当我现在需要数据时,我更喜欢 A,而当我什至可能无法访问相关数据时,除非用户在程序中执行某些操作,我更喜欢 B。

Method A is cleaner and results in optimized SQL query pulling in your related data all at once. Method B is similar to lazy loading the related data as you need it instead.

I prefer A when I need the data now, and B when I may not even access the related data unless the user takes some action in the program.

情域 2024-11-04 06:53:03

我认为这两个不能比较,因为两个例子都有其用法。如果您具有导航属性,第一种绝对是可行的方法,因为在这种情况下,您将在一次往返中将所有数据返回到数据库。如果您没有可用的导航属性,则第二种方法很有用。

I think those two cannot be compared because both examples have their usage. The first is definitely the way to go if you have navigation property because in such case you will return all data in one roundtrip to database. The second approach is useful if you don't have navigation property available.

南巷近海 2024-11-04 06:53:03

两种方式都有效,我想要
知道哪一个是正确的
(更好/更快)。

一般情况下使用 Linq to Entities 导航属性是最佳选择 - 数据会自动为您加入(如果您使用 Include)。

您的第一个查询当前未针对获取计数进行优化,您可以只编写:

count = db.Projects.Include("Tasks").First().Tasks.Count();

否则您将从数据库加载所有相关任务实体。

Both ways are working and I would like
to know, which one is correct
(better/faster).

Using Linq to Entities in general Navigation properties are the way to go - the data is joined in automatically for you (if you use Include).

Your first query is not optimized for getting a count currently, you can just write:

count = db.Projects.Include("Tasks").First().Tasks.Count();

Otherwise you are loading all related task entities from the DB.

苏佲洛 2024-11-04 06:53:03

你为什么不使用这个:

project.Tasks.Load();

Why don't you use this:

project.Tasks.Load();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文