Entity Framework Core не поддерживает автоматическую навигацию - PullRequest
1 голос
/ 27 апреля 2020

У меня есть две сущности, сущность Контакт , у которой есть свойство навигации Покупатель , которая может существовать, и сущность Покупатель , которая имеет свойство навигации Контакт , который должен существовать. Все покупатель имеют ровно один контакт , все контакт могут иметь ноль или один покупатель .

Проблема заключается в том, что при загрузке Контакт Покупателем ) Покупатель не может быть загружен через Eager или Явная загрузка.

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();

При взгляде на базовую базу данных все происходит как ожидалось.

Теперь я пытаюсь загрузить контакт и свойства навигации двумя разными способами, ожидая автоматических исправлений c:

 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 () видит Покупателя как свойство навигации и успешно загружает его в память. Также глядя на _contacts.Buyers показывает, что он находится в памяти.
DetectChanges был добавлен на всякий случай, это не имеет значения.
Загрузка Eager с помощью Include также не вызывает исправлений.
Ленивая загрузка также была опробована и не удалась.

Кто-нибудь знает, как заставить работать автоматическое исправление c?

Свободный 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 Включить Nullable

[Редактировать] Добавив следующую строку кода перед FindAsyn c это приводит к загрузке всего Покупателя в память / кэш, после чего покупатель Contact.Buyer автоматически исправляется после первого FindAsyn c (). Это показывает, что исправления могут произойти. Но я не хочу принудительно загружать всю таблицу.

var test = _context.Buyers.ToList();

1 Ответ

0 голосов
/ 28 апреля 2020

@ ИванСтоев правильно комментирует, что проблема в следующей строке:

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

При замене на:

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

Все автоматические c исправления работают.

См. Также: один-ко-многим-возвращает-пустой-массив-решен

...