实体框架核心不会自动修复导航



我有两个实体,一个实体Contact具有可能存在的导航属性Buyer,另一个实体Buyer具有必须存在的导航特性Contact。所有买家只有一个联系人,所有联系的买家可能为零或一个。

出现的问题是,当加载联系人(具有买方(时,买家无法通过EagerExplicit加载加载。

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之前添加以下代码行,可以将所有Buyer的加载到内存/缓存中,然后在第一个FindAsync((之后自动修复Contact.Buyer Buyer。这表明修复是可能发生的。但我不想强行加载整个表。

var test = _context.Buyers.ToList();

@IvanStoev正确地指出问题出在以下行:

public virtual Contact Contact { get; set; } = new Contact();

当替换为:时

public virtual Contact Contact { get; set; } = null!;

所有自动修复都在工作。

另请参阅:一对多返回空数组求解

最新更新