.NET Linq 查询一对多关系
Posted
技术标签:
【中文标题】.NET Linq 查询一对多关系【英文标题】:.NET Linq query for one-to-many relationsiops 【发布时间】:2021-10-07 08:47:48 【问题描述】:下面的示例显示了客户和发票之间的简单一对多关系。 LINQ 查询检索所有发票和相关客户。我只是想对查询的效率有一个意见,因为就像一个发票有一个客户的递归,客户有很多发票,每个发票都有一个客户,等等。 另外,在只读场景中我可以使用 AsNoTracking() 吗?
public class Customer
public int CustomerID get; set;
public string CustomerName get; set;
[ForeignKey("CustomerID")]
[NotMapped]
public virtual IList<Invoice> Invoices get; set;
public class Invoice
public int InvoiceID get; set;
public int CustomerID get; set;
[ForeignKey("CustomerID")]
public Customer Customer get; set;
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
//........
builder.Entity<Invoice>().ToTable("Invoices")
.HasOne(s => s.Customer).WithMany(c => c.Invoices)
.OnDelete(DeleteBehavior.Restrict);
public class SomeClass
//....
List<Invoice> invList = await context.Invoices.Include(x => x.Customer).toListAsync();
【问题讨论】:
如果代码足够快,则无需尝试替代方案。所以你需要测量。尽可能首先编写代码以确保清晰和易于维护。 是的,用于只读方案AsNoTracking
可以使用,因为您不希望 EF 跟踪它。
【参考方案1】:
我不认为存在递归本身,但当您查看它时可能存在,因为 EF 会在两个方向上链接相关对象
查询将转换为类似的简单内容
SELECT * FROM Invoices JOIN Customers ON ...
如果遇到客户数据,这会导致结果集中的客户信息重复,因为 EF 将它们映射到对象(在枚举结果时创建 Invoice 和 Customer 的实例)的客户它将使用它已经知道的客户实体。
这意味着如果您查看调试器并开始在 Locals 窗口中展开 invList
,您将获得例如发票 ID 1,它是内存地址 0x01 的对象,客户 ID 1 是内存地址 0x82 的对象,你会看到这个客户有20 张发票。如果您在 20 个列表中找到 Invoice ID 1,它将是内存地址 0x01 处的对象。如果你扩展它并查看它的客户,它将是内存地址 0x82 的客户,它有一个包含 20 个 inoice 的列表......等等......你可以永远扩展它们,因为你只是循环回来在相同的两个对象实例之间来回移动,而这 20 张发票只有一个客户。它不会递归地生成更多数据。
在数据加载方面需要更加小心的地方是AsNoTracking
;如果您完全关闭跟踪,那么数据库客户数据中的重复将导致始终生成新的客户实例,即使它们与以前看到的实例具有相同的键。在这种情况下,在本地窗口中展开对象图会看到 Invoice 1,mem address 0x03 有 Customer 1,mem address 0x85,他有一张发票,即 发票 1,mem 地址 0x03。然后,您可以展开 Invoice 2,mem address 0x05 并查看 Customer 1,mem address 0x89 - 与之前相同的客户详细信息但不同的对象实例 (0x85 vx 0x89) p>
实际上,人类买家确实有 20 张与之关联的发票,但在您的对象图中,有 20 个相同客户数据的不同客户实例,它们都有一个发票集合,每个都有一张发票
如果您想避免这种实例爆炸但不跟踪只读方案的数据更改,您可以查看AsNoTrackingWithIdentityResolution
以获取“一张发票与一位客户和 20 张发票......”形状图,但不是为 UPDATE 查询目的跟踪旧/新值
【讨论】:
非常感谢您的详细回复!有道理。以上是关于.NET Linq 查询一对多关系的主要内容,如果未能解决你的问题,请参考以下文章