为什么在简单的一对多关系上使用 LINQ Join?

发布于 2024-12-01 16:06:47 字数 598 浏览 0 评论 0原文

我使用 LINQ to SQL 和实体框架已有几年了,并且始终映射数据库关系以生成相关的导航属性。我总是使用导航属性。

我错过了什么吗?

如果我有一个 Category->Products 一对多类型关系,我会

var redProducts = context.Category.Single(c => c.Name = "red").Products;

经常看到人们在这个网站、在线项目和各种其他网站上进行手动连接。

var employer = from category in context.Categories
               join product in context.Products
               on category.CategoryId equals product.CategoryId
               where category.Name == "red"
               select product;

那么 - 为什么?使用此 Join 语法有什么好处?

I've been using LINQ to SQL and Entity Framework for a few years and I've always mapped my database relationships to generate the relevant navigation properties. And I always use the navigation properties.

Am I missing something?

If I have a Category->Products one-many type relationship, I would use

var redProducts = context.Category.Single(c => c.Name = "red").Products;

I regularly see people doing manual joins, all over this site, in projects online, and various other websites.

var employer = from category in context.Categories
               join product in context.Products
               on category.CategoryId equals product.CategoryId
               where category.Name == "red"
               select product;

So - why? What are the benefits of using this Join syntax?

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

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

发布评论

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

评论(3

伴我老 2024-12-08 16:06:48

这可能是由于将旧代码移植到 linq2sql 造成的。

但是,这两个代码片段在功能上并不相同。

Single 将抛出异常,而 join 在缺少记录的情况下会产生一个空集合。

因此,不使用连接的相同代码将是:

from c in context.Categories where c.Name == "red" from p in c.Products select p;

context.Categories.Where(c=>c.Name == "red").SelectMany(c=>c.Products);

It might result from porting the old code to linq2sql.

However, the two code snippets are not functionally equal.

Single will throw exception, while join yields an empty collection in case of missing record.

So, an equal code without using joins would be:

from c in context.Categories where c.Name == "red" from p in c.Products select p;

or

context.Categories.Where(c=>c.Name == "red").SelectMany(c=>c.Products);
翻身的咸鱼 2024-12-08 16:06:48

对于来自关系思维而不是面向对象思维的人来说,连接可能更常见。如果您从面向对象的角度考虑问题空间,那么处理可以在导航中点的关系比处理 Employee.Customers.Orders.OrderItems.OrderItem 更自然。一堆连接。最初的 ADO.vNext 白皮书很好地讨论了使用模型和关联而不是连接来处理概念模型的优点。不幸的是,我目前找不到该文档。

对我来说,当实体之间没有自然关联时,最好使用联接。例如,如果您尝试在非自然键上连接项目(即在 Customer.StateShipping.State 上连接),您应该使用连接语法(或 SelectMany),而不是在这种情况下在实体之间创建关联。

需要注意的一件事是,连接语法和使用关联可能会导致提供程序生成的连接类型存在差异。通常,连接会转换为内部连接,并排除连接两侧不匹配的项目。要执行(左)外部联接,请使用 DefaultIfEmpty 扩展。

另一方面,在 1-0..* 关系中导航关联通常会转换为右外连接,因为子集合可以合法地为空,并且即使子集合不存在,您也希望包含父集合。您可以使用 !Any() 来捕获没有子记录的情况。

Joins are probably more common for people coming from the Relational mindset rather than the object oriented one. If you think about your problem space from a object orientented perspective, it is much more natural to work with relationships where you can dot through the navigation: Employee.Customers.Orders.OrderItems.OrderItem than to deal with a bunch of joins. The original ADO.vNext whitepaper did a good job of discussing the advantages of using the model and associations rather than joins for dealing with your conceptual models. Unfortunately, I can't find that document at this point.

For me, joins are best used when you don't have natural associations between entities. For example, if you are trying to join items on unnatural keys (i.e. joining on the Customer.State and Shipping.State) you should use the join syntax (or SelectMany) rather than creating associations between your entities in this case.

One thing to be aware of is that the join syntax and using associations can cause differences in the kind of joins that are generated by the provider. Typically a Join translates into an Inner join and excludes items where there is no match on both sides of the join. To perform an (left) outer join, you use the DefaultIfEmpty extension.

Navigating through associations in a 1-0..* relationship on the other hand typically translate into Right Outer joins because the child collection could legitimately be empty and you would want to include the parent even if the child didn't exist. You would use !Any() to trap for cases were there aren't child records.

烟燃烟灭 2024-12-08 16:06:47

这通常是一个错误。

@George 是正确的,您的两个示例在功能上有所不同,与 joinjoin 无关但是,非加入。但您也可以轻松地编写:

var redProducts = context.Category
                         .Where(c => c.Name == "red")
                         .SelectMany(c => c.Products);

...这在功能上与您的 join 示例相同(但从可读性和可维护性 POV 来看优于)。

It's usually a mistake.

@George is correct that your two examples are functionally different in a way which has nothing to do with join vs non-join, however. But you could just as easily write:

var redProducts = context.Category
                         .Where(c => c.Name == "red")
                         .SelectMany(c => c.Products);

...which is functionally identical (but superior from a readability and maintainability POV) to your join example.

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