Entity Framework не заполняет свойства коллекции - PullRequest
0 голосов
/ 03 июля 2018

У меня проблема, очень похожая на те, которые упомянуты в следующих вопросах:

Почему свойство навигации Entity Framework имеет значение null?

Почему свойство навигации EF возвращает ноль?

В моем случае поворот сюжета заключается в том, что свойства коллекции навигации заполняются EF, но только после того, как я запросил DbSet<T> свойства зависимых типов в DbContext. Чтобы прояснить ситуацию, вот как настроена моя модель:

[Table(nameof(Composer))]
internal class ComposerRelationalDto : RelationdalDtoBase
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

    public virtual ICollection<NameRelationalDto> LocalizedNames { get; set; } = new HashSet<NameRelationalDto>();

    public virtual ICollection<ArticleRelationalDto> Articles { get; set; } = new HashSet<ArticleRelationalDto>();
}

[Table(nameof(ComposerName))]
internal class NameRelationalDto : RelationdalDtoBase
{
    [Key]
    public long Id { get; set; }

    [Required]
    [ForeignKey(nameof(Composer))]
    public Guid Composer_Id { get; set; }

    public ComposerRelationalDto Composer { get; set; }
}

[Table(nameof(ComposerArticle))]
internal class ArticleRelationalDto : RelationdalDtoBase
{
    [Key]
    public long Id { get; set; }

    [Index]
    public Guid StorageId { get; set; }

    [Required]
    [ForeignKey(nameof(Composer))]
    public Guid Composer_Id { get; set; }

    public ComposerRelationalDto Composer { get; set; }

    [Required]
    [MaxLength(5)]
    public string Language { get; set; }
}

В соответствующем репозитории я фильтрую ComposerRelationalDto объекты по их именам:

DbContext.Set<NameRelationalDto>().Where(nameWhereClause).GroupBy(n => n.Composer_Id).Select(group => group.FirstOrDefault().Composer)

Набор ComposerRelationalDto s содержит пустые коллекции для свойств Articles и LocalizedNames, даже если данные были правильно сохранены в базе данных. Однако если я загружаю все DTO типа ArticleRelationalDto и NameRelationalDto в QuickWatch во время отладки , , тогда тот же фильтр больше не возвращает пустые коллекции, и все соответствующие объекты присутствуют в свойствах коллекции. .

То, что я до сих пор пробовал, было

  1. включить отложенную загрузку и явное создание прокси

  2. настроить отношения один-ко-многим вручную:

    modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.LocalizedNames).WithRequired(n => n.Composer).HasForeignKey(n => n.Composer_Id);
    modelBuilder.Entity<ComposerRelationalDto>().HasMany(c => c.Articles).WithRequired(a => a.Composer).HasForeignKey(a => a.Composer_Id);
    
  3. и, наконец, я только что попробовал поиграться с DbQuery<T>.Include() методом DbContext.Set<ComposerRelationalDto>().Include(c => c.Articles), который, к сожалению, выдает исключение ArgumentNullException из одного из внутренних методов, которые он вызывает.

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

Редактировать : Я изменил свойство Composer зависимых типов, чтобы оно было виртуальным. Однако проблема сохраняется.

После использования .Select(group => group.FirstOrDefault().Composer).Include(c => c.Articles).Include(c => c.LocalizedNames) теперь я больше не получаю ArgumentNullException (может быть, я получаю ArgumentNullException, потому что я изначально использовал .Include() в QuickWatch?), А скорее MySqlException: неизвестный столбец ' Join2.Id 'в' списке полей '; Словарь данных содержит Ключ: «Код ошибки сервера» Значение: 1054. Также сгенерированный SQL смехотворно велик и едва читаем.

1 Ответ

0 голосов
/ 07 июля 2018

Я понял это. Это был модификатор доступа internal в объявлениях классов. Позор, потому что я действительно хотел сделать остальную часть решения полностью независимой от базы данных (отсюда и необычное использование DTO для кода в первую очередь вместо реальных сущностей, как уже было указано в комментариях), и я хотел применить это в строгой манере.

В любом случае, я немного поигрался с модификаторами доступа, и я смог справиться только с ограничением видимости объекта БД, сделав их public с помощью internal protected конструкторов. Любая другая комбинация видимости класса и ctor, включающая internal, приводила к повторному появлению проблемы. Не повезло и с InternalsVisibleTo.

Этот вопрос - Код Entity Framework Первый внутренний класс - возможно ли это? - кажется, предполагает, что использование внутреннего класса не должно быть проблемой для EF, но, похоже, это, в конце концов, что-то вроде проблемы. Если этого не было (ответ Джули Лерман датируется 2011 годом), то сейчас. Я сейчас использую EF 6.2.0.

...