下面的示例顯示了客戶和發票之間的簡單一對多關系。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();
}
uj5u.com熱心網友回復:
我不認為遞回本身存在,但是當您查看它時可能存在遞回,只是因為 EF 會在兩個方向上鏈接相關物件
查詢將轉換為簡單的東西
SELECT * FROM Invoices JOIN Customers ON ...
對于擁有多個發票的客戶,這會導致結果集中的客戶資訊重復,但由于 EF 將它們映射到物件(在列舉結果時創建 Invoice 和 Customer 的實體),如果遇到客戶資料,它已經看到在它使用它已經知道的 Customer 物體之前。
這意味著如果您查看除錯器并開始invList在 Locals 視窗中展開,您將得到例如發票 ID 1,它是記憶體地址 0x01 處的物件,其客戶 ID 1 是記憶體地址處的物件0x82,你會看到這個客戶有 20 張發票。如果您在 20 個串列中找到發票 ID 1,它將是記憶體地址 0x01 處的物件。如果你展開它并查看它的 Customer,它將是記憶體地址 0x82 處的 Customer,它有一個包含 20 個 inoices 的串列......等等......你可以一直擴展它們,因為你只是在回圈回傳在相同的兩個物件實體之間來回切換,并且這 20 個發票只有一個客戶。它不會遞回地生成更多資料。
在資料加載方面必須更加小心的地方是AsNoTracking; 如果您完全關閉跟蹤,那么資料庫客戶資料中的重復將導致一直生成新的客戶實體,即使它們與以前看到的實體具有相同的密鑰。在這種情況下,在 locals 視窗中展開物件圖會看到Invoice 1, mem address 0x03有Customer 1,mem address 0x85有一張發票,即Invoice 1, mem address 0x03。然后,您可以展開Invoice 2, mem address 0x05并查看Customer 1, mem address 0x89 - 相同的客戶詳細資訊,但與之前不同的物件實體 (0x85 vx 0x89)
實際上,人類買家確實有 20 張與之關聯的發票,但在您的物件圖中,有 20 個不同的 Customer 實體,它們具有相同的客戶資料,所有這些實體都有一個發票集合,每個實體帶有一個 Invoice
如果您想避免這種實體爆炸但不跟蹤只讀場景的資料更改,您可以查看AsNoTrackingWithIdentityResolution“一張發票,一個客戶有 20 張發票......”形狀的圖表,但不跟蹤舊/新值UPDATE 查詢目的
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/318207.html
上一篇:基于給定條件的LINQ過濾器串列
