Миграции изначально работали, но теперь выдают странные ошибки.

Вопрос или проблема

Короче говоря, я успешно выполнил начальную миграцию с EF Core 8. Однако вскоре я нашел несколько довольно незначительных моментов здесь и там и попытался их исправить, но попытки создать новую миграцию в дальнейшем закончились ошибками с довольно странными сообщениями. Это озадачивает, потому что начальная миграция прошла гладко, но теперь она просто отказывается работать.

Я создал отдельный проект и пытался добавлять модели по одной, пока это не перестало работать.

Вот настройка, при которой проект все еще работает:

internal class Dictionary
{
    public string Name { get; set; }
    public bool IsEnabled { get; set; }
    public ICollection<DictionaryEntry> Entries { get; set; }
}

internal class DictionaryEntry
{
    public string Name { get; set; }
    public bool IsEnabled { get; set; }
    public Dictionary Dictionary { get; set; }
}

internal abstract class DictionaryEntry<TValue>: DictionaryEntry
{
    public TValue Value { get; set; }
}

internal abstract class GroupedEntry<TValue, TEntryGroup>: DictionaryEntry<TValue>
    where TEntryGroup : DictionaryEntry
{
    public virtual TEntryGroup EntryGroup { get; set; }
}

internal class EntryGroup<TEntry>: DictionaryEntry
    where TEntry : DictionaryEntry
{
    public virtual ICollection<TEntry> Entries { get; set; } 
    public virtual EntryGroup<TEntry> Parent { get; set; }
    public virtual ICollection<EntryGroup<TEntry>> Children { get; set; }
}

internal class EntryGroup<TGroupEntry, TEntry>: EntryGroup<TEntry>
    where TGroupEntry : DictionaryEntry
    where TEntry : DictionaryEntry
{
    public virtual TGroupEntry GroupEntry { get; set; } = null!;
}

internal class EntryClassA: DirectoryEntry<uint>
{
    public virtual EntryClassB LinkedDocumentation { get; set; }
}

internal class EntryClassB: GroupedEntry<uint, EntryGroup_EntryClassAB>;

internal class EntryGroup_EntryClassAB: EntryGroup<EntryClassB, EntryClassA>

Добавление этих классов вызывает ошибки:

internal abstract class Entry_ClassCBase: GroupedEntry<uint, EntryGroup_ClassC>;
internal class Entry_ClassCGroup: Entry_ClassCBase;
internal class Entry_ClassC: Entry_ClassCBase;
internal class EntryGroup_ClassC: EntryGroup<Entry_ClassCGroup, Entry_ClassC>;

В этом конкретном случае это связано с

Не удалось создать ‘DbContext’ типа ”. Исключение ‘Нельзя определить зависимую сторону для связи «один к одному» между ‘EntryGroup_ClassC.GroupEntry’ и ‘Entry_ClassCGroup.EntryGroup’. Чтобы определить зависимую сторону отношений, настройте свойство внешнего ключа. Если эти навигации не должны быть частью одной и той же связи, настройте их независимо через отдельные цепочки методов в ‘OnModelCreating’. Смотрите https://go.microsoft.com/fwlink/?LinkId=724062 для получения дополнительных сведений.

Но в основном приложении модель уже включала те же классы, когда первая миграция была успешно создана, так что я не понимаю внезапного появления ошибок. Я могу аккуратно исправить ошибки одну за другой, но, конечно, не хочу этого делать. Моя единственная теория заключается в том, что, когда я устранил эти проблемы, я, вероятно, перемешал какой-то код, который заставил модель работать, но не понимаю, какой именно.

Вот мой контекст:

namespace Program
{
    sealed class CultureInfoConverter: ValueConverter<CultureInfo, string>
    {
        public CultureInfoConverter() : base(static (v) => v.Name, static (v) => CultureInfo.GetCultureInfo(v)) { }
    }

    internal partial class Context(DbContextOptions<Context> options): DbContext(options)
    {
        public DbSet<Dictionary> Dictionaries { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            _ = modelBuilder.
                HasCollation("en_natural", locale: "en-u-kn-true", provider: "icu", deterministic: false);
            _ = modelBuilder.UseHiLo(null);

            _ = modelBuilder.Owned<Oid>();
            _ = modelBuilder.Owned<Version>();

            _ = modelBuilder.Entity<Dictionary>().
                HasDiscriminator();
            _ = modelBuilder.Entity<Dictionary>().Property<uint>("RowVersion").
                IsRowVersion();
            _ = modelBuilder.Entity<DictionaryEntry>().
                HasDiscriminator();
            _ = modelBuilder.Entity<DictionaryEntry>().Property<uint>("RowVersion").
                IsRowVersion();
            _ = modelBuilder.Entity<Dictionary>().Property<ulong>("Id");
            _ = modelBuilder.Entity<DictionaryEntry>().Property<ulong>("Id");
        }
        protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
        {
            _ = configurationBuilder.Properties<string>().
                UseCollation("en_natural").
                AreUnicode();

            _ = configurationBuilder.Properties<CultureInfo>().
                HaveConversion<CultureInfoConverter>();
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => _ = optionsBuilder.UseExceptionProcessor();
    }
}

Ответ или решение

Проблемы с миграциями в Entity Framework Core 8: Разбор и решение

При работе с Entity Framework Core (EF Core) возникают ситуации, когда миграции не проходят, несмотря на успешное выполнение первоначальной миграции. В данном случае мы видим, что после внесения незначительных правок ошибки начали проявляться в модели. Рассмотрим подробно возможные причины этих ошибок и способы их устранения.

Причины ошибок миграции

  1. Неправильная настройка отношений между сущностями:
    Ваша ошибка явно указывает на проблему в определении зависимостей между сущностями, особенно в отношении "один к одному". В случае с классами EntryGroup_ClassC и Entry_ClassCGroup, EF Core не может определить, какая из сущностей является зависимой.

    Рассмотрим следующий фрагмент кода:

    internal abstract class Entry_ClassCBase : GroupedEntry<uint, EntryGroup_ClassC> { }

    Чтобы устранить данную ошибку, убедитесь, что вы четко указываете внешние ключи и конфигурируете отношения в методе OnModelCreating. Например:

    modelBuilder.Entity<Entry_ClassCGroup>()
       .HasKey(e => e.Id);
    
    modelBuilder.Entity<Entry_ClassCGroup>()
       .HasOne(e => e.EntryGroup)
       .WithOne(e => e.GroupEntry)
       .HasForeignKey<Entry_ClassCGroup>(e => e.GroupEntryId);
  2. Изменения в структуре модели:
    Если вы переместили код или изменили его таким образом, что структура классов не соответствует базе данных, это может привести к конфликтам. Должны быть соблюдены правила именования и иерархии, чтобы EF Core корректно обрабатывал наследование и отношения.

  3. Кэширование данных:
    Иногда, даже если код был изменен, приложение может задействовать кэшированные данные или старые миграции. Это можно устранить, выполнив команду Update-Database или dotnet ef database update, которая приведет базу данных в актуальное состояние относительно ваших миграций.

  4. Проблемы с контекстом DbContext:
    Проверьте, что все свойства DbSet определены корректно, поскольку они напрямую влияют на генерацию миграций. Например:

    public DbSet<Dictionary> Dictionaries { get; set; }

Как решать возникающие ошибки

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

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

  3. Проверка миграций:
    Используйте команду dotnet ef migrations list для проверки текущих миграций. Убедитесь, что в этой информации нет конфликтующих миграций или других ошибок.

  4. Использование отладчика:
    Запуск отладчика в Visual Studio может помочь вам понять, где именно происходит сбой, особенно в методе OnModelCreating.

  5. Чистка базы данных:
    В крайних случаях, если структура миграций изрядно запуталась, можно удалить все существующие миграции и заново создать их с помощью Add-Migration InitialCreate. Однако будьте осторожны, так как это приведет к потере данных, если база данных уже содержит важную информацию.

Заключение

Ошибки миграции в Entity Framework Core могут быть связаны с недостаточной конфигурацией отношений между сущностями, изменениями в модели или кэшированием данных. Проверьте ваши классы, четко определите отношения и используйте подходящие инструменты для отладки и анализа. Если потребуется, производите изменения постепенно, чтобы установить источник ошибки. Это поможет улучшить процесс разработки и упростить дальнейшую работу с базой данных.

Оцените материал
Добавить комментарий

Капча загружается...