Entity Framework 6: Включите вложенное nullable много-много детей - PullRequest
1 голос
/ 16 мая 2019

Мое включение всегда пусто.Хотя я вижу, что в базе данных SQL есть ссылки между родителем и потомком.

IQueryable<ManageProductItems> models = db.Products
    .Include(m => m.Collections).Include(m => m.Images)
    .Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
    .Select....

Я хочу включить вложенный Products -> VariantDetails -> Variants -> VariantType

Результат всегда дает мне Variants = null.

Вот конфигурация модели:

public class Product
{
    ...
    public ICollection<ProductCollection> Collections { get; set; }
    public ICollection<ProductVariantDetail> VariantDetails { get; set; }
    public ICollection<ProductImage> Images { get; set; }

    public ICollection<ProductVariantType> ProductVariantTypes { get; set; }
    public ICollection<ProductVariant> ProductVariants { get; set; }
}

public class ProductVariantDetail
{
    ....
    public ICollection<ProductVariant> Variants { get; set; }

    [ForeignKey("Product")]
    public Guid ProductId { get; set; }

    [CascadeDelete]
    public virtual Product Product { get; set; }

    public virtual ProductImage ProductImage { get; set; }
}

public class ProductVariant
{
    ...
    [ForeignKey("VariantType")]
    public Guid VariantTypeId { get; set; }

    [CascadeDelete]
    public virtual ProductVariantType VariantType { get; set; }

    public ICollection<ProductVariantDetail> VariantDetails { get; set; }

    [ForeignKey("Product")]
    public Guid? ProductId { get; set; }
    public Product Product { get; set; }
}

public class ProductVariantType
{
    ...
    [ForeignKey("Product")]
    public Guid? ProductId { get; set; }
    public Product Product { get; set; }
}

В SQL-сервере есть таблица dbo.ProductVariantDetailProductVariants, которая отображает ProductVariantDetail и ProductVariant.Отображенные идентификаторы из обеих таблиц верны.

Но это происходит:

Products -> VariantDetails -> Variants = null


РЕДАКТИРОВАТЬ 1

Я попытался просто сократить запрос с помощью:

var xxx = db.ProductVariantDetails.Include(m => m.Variants).ToList();

Варианты загружаются правильно.Поэтому я уверен, что есть проблема с вложенным включением или ошибкой.


РЕДАКТИРОВАНИЕ 2

Это так странно.Поэтому я попытался поиграть с кодом.Я поставил это:

var xxx = db.ProductVariantDetails.Include(m => m.Variants.Select(z => z.VariantType)).ToList();

IQueryable<ManageProductItems> models = db.Products
    .Include(m => m.Collections).Include(m => m.Images)
    .Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
    .Select....

Таким образом, xxx кеширует VariantType, тогда когда models запрашивает целые объекты, Product -> VariantDetails -> Variants -> VariantType загружается правильно.Если я просто запрашиваю models без xxx, проблема все еще сохраняется.

Так что каким-то образом db необходимо кэшировать Variants и VariantTypes до этого.

Какя могу решить это?

Ответы [ 2 ]

0 голосов
/ 16 мая 2019

Вам не хватает включения:

db.Products
  .Include(m => m.Collections)
  .Include(m => m.Images)
  .Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
  .Select(...);

Вы никогда не просили загрузить самих Variants. Когда Variants не загружены, все последующие связанные объекты игнорируются.

Попробуйте следующее:

db.Products
  .Include(m => m.Collections)
  .Include(m => m.Images)
  .Include(m => m.VariantDetails.Select(x => x.Variants))
  .Include(m => m.VariantDetails.Select(x => x.Variants.Select(z => z.VariantType)))
  .Select(...);

Однако может быть вторичная проблема, которую вы скрыли, скрыв оператор Select. Я добавил второй ответ для решения этой потенциальной вторичной проблемы.

0 голосов
/ 16 мая 2019

Примечание. Это второй ответ, посвященный второстепенной проблеме в вашем коде.Сначала прочитайте другой ответ, так как я подозреваю, что это будет самый прямой ответ на ваш вопрос.

Ваш Select отменяет / игнорирует ваш Include.Include (явно) используется для неявного и автоматического извлечения связанных сущностей, но Select явно запрашивает другое возвращаемое значение, которое переопределяет установленные вами правила неявного включения.

Некоторые примеры, демонстрирующие, как оноworks:

var list = db.Products
             .ToList();

Возвращает список продуктов без загруженных связанных объектов.

var list = db.Products
             .Include(m => m.ProductOwner)
             .ToList();

Возвращает список продуктов с загруженным свойством ProductOwner.

var list = db.Products
             .Select(p => p.Name)
             .ToList();

var list2 = db.Products
             .Include(m => m.ProductOwner)
             .Select(p => p.Name)
             .ToList();

Оба списка представляют собой список строк (с названиями продуктов).Делать Include было неуместно.

var list = db.Products
             .Select(p => p.ProductOwner.Name)
             .ToList();

var list2 = db.Products
             .Include(m => m.ProductOwner)
             .Select(p => p.ProductOwner.Name)
             .ToList();

Оба списка представляют собой список строк (с именами владельцев продуктов).Выполнение Include не имело значения.

Это важная часть, на которую следует обратить внимание: вам не понадобился Include, чтобы получить имя связанной ProductOwner сущности .Это связано с тем, что ваш оператор Select явно просил EF извлечь данные связанных сущностей, и, следовательно, EF не требовался Include, потому что ему все равно не требовалась неявная загрузка связанных сущностей.

Это поведениеподдерживается для любого оператора Select, включая те, в которых вы все еще используете полный объект Product.Что означает:

var list = db.Products
             .Select(p => new { Product = p })
             .ToList();

var list2 = db.Products
             .Include(m => m.ProductOwner)
             .Select(p => new { Product = p })
             .ToList();

В обоих случаях вы получите Product сущность без его ProductOwner, потому что EF слушает Select и игнорирует любые другие инструкциио том, какие данные загружать (включая Include).

...