Entity Framework Core 不会自动修复导航
Entity Framework Core doesn't automatically fix-up navigation
我有两个实体,一个实体 Contact 可能存在导航 属性 Buyer,一个实体具有必须存在的导航 属性 联系人 的买家。所有买家都有一个联系人,所有联系人可能有零个或一个买家的.
出现的问题是,当加载 Contact(有 Buyer)时,Buyer 无法通过 Eager 或 Explicit 加载。
public class Contact
{
public int ContactID { get; set; }
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string Email { get; set; } = null!;
public virtual Buyer? Buyer { get; set; }
}
public class Buyer
{
public int BuyerID { get; set; }
public string CompanyName { get; set; } = default!;
public string ProductName { get; set; } = default!;
public int ContactID { get; set; }
public virtual Contact Contact { get; set; } = new Contact();
}
当我创建实体时:
// existing Contact already initialized with Buyer == null and added
var newBuyer = new Buyer() { CompanyName = "Acme", ProductName = "Anvil" };
newBuyer.ContactID = contactID;
// Load the reference to the Contact
newBuyer.Contact = await _context.Contacts.SingleOrDefaultAsync(c => c.ContactID == contactID);
// error checking elided (but in this test it is not failing)
// newBuyer.Contact.Buyer is null if examined
_context.Buyers.Add(newBuyer);
// newBuyer.Contact.Buyer is now newBuyer, automatic fix-up
await _context.SaveChangesAsync();
查看底层数据库,一切都符合预期。
现在我尝试以两种不同的方式加载联系人和导航属性,期望自动修复:
Contact = await _context.Contacts.FindAsync(id);
// The Contact.Buyer is null here as expected, so explicitly Load
_context.Entry(Contact).Reference(c => c.Buyer).Load();
// The Contact.Buyer is still null here, so try DetectChanges
_context.ChangeTracker.DetectChanges();
// The Contact.Buyer is still null here, so try again with Eager Loading
Contact = await _context.Contacts.Include(c => c.Buyer).FirstOrDefaultAsync(m => m.ContactID == id);
// The Contact.Buyer is still null here! What is wrong?
在调试器中进行跟踪时,第一个显式 Load() 将 Buyer 视为导航 属性 并成功加载
它进入记忆。还看_contacts.Buyers表明在内存中
添加 DetectChanges 只是为了以防万一,没有任何区别。
使用 Include 的急切加载也不会导致修复。
也尝试过延迟加载,但失败了。
有谁知道如何让自动修复工作?
流利的API:
modelBuilder.Entity<Contact>()
.HasKey("ContactID");
modelBuilder.Entity<Buyer>()
.HasKey(p => p.BuyerID);
modelBuilder.Entity<Buyer>()
.HasOne<Contact>(p => p.Contact)
.WithOne("Buyer")
.HasForeignKey("Buyer", "ContactID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
注释: EF Core 3.1.3 Net Core API 3.1.0 可空启用
[编辑] 通过在 FindAsync 之前添加以下代码行,它会导致所有买家加载到 memory/cache,然后 Contact.Buyer 买家会在第一个 FindAsync() 之后自动修复.这表明可能会发生修正。但是又不想强行加载整个table.
var test = _context.Buyers.ToList();
@IvanStoev 正确评论问题出在以下行:
public virtual Contact Contact { get; set; } = new Contact();
替换为:
public virtual Contact Contact { get; set; } = null!;
所有自动修正都在工作。
另见:
我有两个实体,一个实体 Contact 可能存在导航 属性 Buyer,一个实体具有必须存在的导航 属性 联系人 的买家。所有买家都有一个联系人,所有联系人可能有零个或一个买家的.
出现的问题是,当加载 Contact(有 Buyer)时,Buyer 无法通过 Eager 或 Explicit 加载。
public class Contact
{
public int ContactID { get; set; }
public string FirstName { get; set; } = null!;
public string LastName { get; set; } = null!;
public string Email { get; set; } = null!;
public virtual Buyer? Buyer { get; set; }
}
public class Buyer
{
public int BuyerID { get; set; }
public string CompanyName { get; set; } = default!;
public string ProductName { get; set; } = default!;
public int ContactID { get; set; }
public virtual Contact Contact { get; set; } = new Contact();
}
当我创建实体时:
// existing Contact already initialized with Buyer == null and added
var newBuyer = new Buyer() { CompanyName = "Acme", ProductName = "Anvil" };
newBuyer.ContactID = contactID;
// Load the reference to the Contact
newBuyer.Contact = await _context.Contacts.SingleOrDefaultAsync(c => c.ContactID == contactID);
// error checking elided (but in this test it is not failing)
// newBuyer.Contact.Buyer is null if examined
_context.Buyers.Add(newBuyer);
// newBuyer.Contact.Buyer is now newBuyer, automatic fix-up
await _context.SaveChangesAsync();
查看底层数据库,一切都符合预期。
现在我尝试以两种不同的方式加载联系人和导航属性,期望自动修复:
Contact = await _context.Contacts.FindAsync(id);
// The Contact.Buyer is null here as expected, so explicitly Load
_context.Entry(Contact).Reference(c => c.Buyer).Load();
// The Contact.Buyer is still null here, so try DetectChanges
_context.ChangeTracker.DetectChanges();
// The Contact.Buyer is still null here, so try again with Eager Loading
Contact = await _context.Contacts.Include(c => c.Buyer).FirstOrDefaultAsync(m => m.ContactID == id);
// The Contact.Buyer is still null here! What is wrong?
在调试器中进行跟踪时,第一个显式 Load() 将 Buyer 视为导航 属性 并成功加载
它进入记忆。还看_contacts.Buyers表明在内存中
添加 DetectChanges 只是为了以防万一,没有任何区别。
使用 Include 的急切加载也不会导致修复。
也尝试过延迟加载,但失败了。
有谁知道如何让自动修复工作?
流利的API:
modelBuilder.Entity<Contact>()
.HasKey("ContactID");
modelBuilder.Entity<Buyer>()
.HasKey(p => p.BuyerID);
modelBuilder.Entity<Buyer>()
.HasOne<Contact>(p => p.Contact)
.WithOne("Buyer")
.HasForeignKey("Buyer", "ContactID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
注释: EF Core 3.1.3 Net Core API 3.1.0 可空启用
[编辑] 通过在 FindAsync 之前添加以下代码行,它会导致所有买家加载到 memory/cache,然后 Contact.Buyer 买家会在第一个 FindAsync() 之后自动修复.这表明可能会发生修正。但是又不想强行加载整个table.
var test = _context.Buyers.ToList();
@IvanStoev 正确评论问题出在以下行:
public virtual Contact Contact { get; set; } = new Contact();
替换为:
public virtual Contact Contact { get; set; } = null!;
所有自动修正都在工作。
另见: