Вопрос или проблема
Короче говоря, я успешно выполнил начальную миграцию с 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) возникают ситуации, когда миграции не проходят, несмотря на успешное выполнение первоначальной миграции. В данном случае мы видим, что после внесения незначительных правок ошибки начали проявляться в модели. Рассмотрим подробно возможные причины этих ошибок и способы их устранения.
Причины ошибок миграции
-
Неправильная настройка отношений между сущностями:
Ваша ошибка явно указывает на проблему в определении зависимостей между сущностями, особенно в отношении "один к одному". В случае с классами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);
-
Изменения в структуре модели:
Если вы переместили код или изменили его таким образом, что структура классов не соответствует базе данных, это может привести к конфликтам. Должны быть соблюдены правила именования и иерархии, чтобы EF Core корректно обрабатывал наследование и отношения. -
Кэширование данных:
Иногда, даже если код был изменен, приложение может задействовать кэшированные данные или старые миграции. Это можно устранить, выполнив командуUpdate-Database
илиdotnet ef database update
, которая приведет базу данных в актуальное состояние относительно ваших миграций. -
Проблемы с контекстом DbContext:
Проверьте, что все свойства DbSet определены корректно, поскольку они напрямую влияют на генерацию миграций. Например:public DbSet<Dictionary> Dictionaries { get; set; }
Как решать возникающие ошибки
-
Четко определите отношения:
Для предотвращения ошибок, связанных с определения зависимых сторон отношений, проще всего использовать явное указание внешних ключей. Это поможет EF Core точно определить, какие свойства выступают в качестве внешних ключей. -
Постепенное добавление классов:
Так как вы упоминали, что добавляли свои классы один за другим, можете вернуться к первоначальной версии и добавлять их по одному, проверяя каждую миграцию. Это поможет понять, какой конкретный класс вызывает проблему. -
Проверка миграций:
Используйте командуdotnet ef migrations list
для проверки текущих миграций. Убедитесь, что в этой информации нет конфликтующих миграций или других ошибок. -
Использование отладчика:
Запуск отладчика в Visual Studio может помочь вам понять, где именно происходит сбой, особенно в методеOnModelCreating
. -
Чистка базы данных:
В крайних случаях, если структура миграций изрядно запуталась, можно удалить все существующие миграции и заново создать их с помощьюAdd-Migration InitialCreate
. Однако будьте осторожны, так как это приведет к потере данных, если база данных уже содержит важную информацию.
Заключение
Ошибки миграции в Entity Framework Core могут быть связаны с недостаточной конфигурацией отношений между сущностями, изменениями в модели или кэшированием данных. Проверьте ваши классы, четко определите отношения и используйте подходящие инструменты для отладки и анализа. Если потребуется, производите изменения постепенно, чтобы установить источник ошибки. Это поможет улучшить процесс разработки и упростить дальнейшую работу с базой данных.