Entity Framework Core .Include () фильтрует запрос - PullRequest
1 голос
/ 25 марта 2020

Я использую EF Core 3.1.3 и у меня есть два запроса:

var test = await _unitOfWork.Context.PersonEmail
    .OrderBy(e => e.EmailId)
    .Take(10)
    .Include(e => e.EmailRecord)
    .ToListAsync();
var test2 = await _unitOfWork.Context.PersonEmail
    .OrderBy(e => e.EmailId)
    .Take(10)
    .ToListAsync();

Я ожидал, что оба запроса вернут 10 результатов, но для 6 элементов из запроса test иметь null для свойства EmailRecord (поскольку таблица EmailRecord не содержит записи для этих конкретных элементов). Однако в действительности запрос test возвращает только 4 результата, тогда как запрос test2 возвращает ожидаемые значения 10.

Сущности объявляются так:

[Table("PersonEmail")]
public class PersonEmail
{
    public Guid PersonId { get; set; }
    public Guid EmailId { get; set; }

    [ForeignKey("PersonId, EmailId")]
    public EmailRecord EmailRecord { get; set; }
}

[Table("EmailRecord")]
public class EmailRecord
{
    public Guid PersonId { get; set; }
    public Guid EmailId { get; set; }
    public DateTimeOffset LastUpdated { get; set; }
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PersonEmail>().HasKey(x => new { x.PersonId, x.EmailId });
    modelBuilder.Entity<EmailRecord>().HasKey(x => new { x.PersonId, x.EmailId });
}

1 Ответ

1 голос
/ 25 марта 2020

Это из-за (неправильной) конфигурации отношений.

То, как вы ее определили

[ForeignKey("PersonId, EmailId")]

в PersonEmail делает это отношение один к одному с PersonEmail будучи зависимым (из-за ФК) и EmailRecord являющимся принципалом .

Если это так, то "поскольку таблица EmailRecord не содержит записи для этих конкретных элементов" просто не может произойти из-за принудительного ограничения FK. И из-за этого EF Core 3.0+ Include генерирует правильно inner join, который не должен фильтровать основной набор, но фактически фильтрует его из-за фактического отношения данных в базе данных.

To исправить это, вы должны отразить фактические отношения, которые, кажется, наоборот: один к одному с основным PersonEmail и зависимым EmailRecord.

Удалите вышеуказанный атрибут [ForeignKey] и добавьте следующая свободная конфигурация:

modelBuilder.Entity<PersonEmail>()
    .HasOne(x => x.EmailRecord)
    .WithOne()
    .HasForeignKey<EmailRecord>(x => new { x.PersonId, x.EmailId });

Теперь Include будет использовать left outer join и не будет фильтровать записи PersonEmail.

Для получения дополнительной информации см. Отношения - Документация EF Core один на один .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...