Включение нескольких свойств навигации коллекции «многие ко многим» - PullRequest
0 голосов
/ 21 февраля 2019

Описание

При попытке нетерпеливо .Include() Многие-ко-многим ICollection свойств уже вложенного ICollection я получаю EntityCommandCompilationException с innerException: System.NotSupportedException: APPLY joins are not supported.

  • Существуют ли (подходящие) обходные пути или это просто не поддерживается EF6 / SQLite?Если не поддерживается, сработает ли миграция на EntityFramework.Core?
  • Если некоторые из вас смогут подтвердить, что это ограничение, я бы создал проблему на трекере SQLite

Краткое описание проблемы

// Bare minimum model definitions - see below for a full implementation

public class Mode
{
    [Key] public int Id { get; set; }
}

public class Type
{
    [Key] public int Id { get; set; }
}

public class Preset
{
    [Key] public string PresetId { get; set; }

    /* Note: Both Types and Modes are Many-To-Many Entity Relationship configured
     * using Join Table/Fluent API */
    public ICollection<Type> Types { get; set; } = new List<Type>();
    public ICollection<Mode> Modes { get; set; } = new List<Mode>();
}

public class Plugin
{
    [Key] public int Id { get; set; }
    public ICollection<Preset> Presets { get; set; } = new List<Preset>();
}

public void test ()
{
    context.Plugins
        .Include("Presets.Modes")
        .Include("Presets.Types")
        .Load();
}

// EntityCommandCompilationException An error occurred while preparing the command definition. See the inner exception for details.
// innerException System.NotSupportedException: APPLY joins are not supported

Это основной код, который не работает.Ниже приведен полный код и описание реализации моделей.

В отличие от этого, включая один из двух ICollection навигационных свойств, работает нормально:

context.Plugins
    .Include("Presets.Modes")
    .Load();

Кроме того, включая более одного ICollection на одном уровне, работает нормально:

context.Presets
    .Include("Modes")
    .Include("Types")
    .Load();

Дополнительная информация, окружающая среда

  • Проблема затрагивает только EntityFramework6 вместе с System.Data.SQLite.EF6 .Насколько я знаю, EntityFramework.SqlServerCompact не затронут.
  • Я использую EF6 Code-First, я не пробовал EF6 Model-First или Database-First (и переключаюсь на любой изэто неприменимое решение)
  • Проблема возникает только со свойствами навигации коллекции «многие ко многим», и только если я пытаюсь загрузить несколько на одном уровне
  • альтернативы, в том числе Select (), которая выдает то же исключение
  • Я не пробовал создавать ручные объединения или запросы, так как это привело бы к чрезвычайной потере обслуживания кода в моем проекте
  • На данный момент,Я полагаю, что основной причиной является ограничение реализации SQLite EF6 (которая, кажется, не документирована), а не то, что я мог бы легко исправить с помощью кода
  • Я нашел только один подобный вопрос StackOverflow относительно нескольких .Include(), и (ужасно использовать) средство отслеживания ошибок SQLite, а также списки рассылки, кажется, не упоминаютОсобая проблема
  • Полный исходный код, включая тестовую базу данных с тестовыми данными, можно найти в моем GitHub EntityFrameworkResearch репозитории .В частности, Определения модели , DbContext и код репро

Код ссылки

public class Mode
{
    [Key] public int Id { get; set; }

    public ICollection<Plugin> Plugins { get; set; }
    public ICollection<Preset> Presets { get; set; }

    public string Name { get; set; }
}

public class Type
{
    [Key] public int Id { get; set; }

    public ICollection<Plugin> Plugins { get; set; } = new List<Plugin>();
    public ICollection<Preset> Presets { get; set; } = new List<Preset>();

    public string Name { get; set; }
    public string SubTypeName { get; set; }
}

public class Plugin
{
    [Key] public int Id { get; set; }
    public ICollection<Preset> Presets { get; set; } = new List<Preset>();

    public ICollection<Type> DefaultTypes { get; set; } = new List<Type>();
    public ICollection<Mode> DefaultModes { get; set; } = new List<Mode>();
}

public class Preset
{
    [Key] public string PresetId { get; set; } = Guid.NewGuid().ToString();

    [ForeignKey("Plugin")] public int PluginId { get; set; }

    public Plugin Plugin { get; set; }
    public ICollection<Type> Types { get; set; } = new List<Type>();
    public ICollection<Mode> Modes { get; set; } = new List<Mode>();
}

public class ApplicationDatabaseContext : DbContext
{
    // Constructor and further database initialization omitted for clarity

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {

        modelBuilder.Entity<Plugin>()
            .HasMany(p => p.DefaultModes)
            .WithMany(q => q.Plugins)
            .Map(mc => mc.MapLeftKey("PluginId").MapRightKey("ModeId").ToTable("PluginModes"));

        modelBuilder.Entity<Plugin>()
            .HasMany(p => p.DefaultTypes)
            .WithMany(q => q.Plugins)
            .Map(mc => mc.MapLeftKey("PluginId").MapRightKey("TypeId").ToTable("PluginTypes"));


        modelBuilder.Entity<Preset>()
            .HasMany(p => p.Types)
            .WithMany(q => q.Presets)
            .Map(mc =>mc.MapLeftKey("PresetId").MapRightKey("TypeId").ToTable("PresetTypes"));

        modelBuilder.Entity<Preset>()
            .HasMany(p => p.Modes)
            .WithMany(q => q.Presets)
            .Map(mc => mc.MapLeftKey("PresetId").MapRightKey("ModeId").ToTable("PresetModes"));
    }

    public DbSet<Plugin> Plugins { get; set; }
    public DbSet<Preset> Presets { get; set; }
    public DbSet<Mode> Modes { get; set; }
    public DbSet<Type> Types { get; set; }
}
...