Измените свойство IDENTITY столбца, столбец необходимо удалить и создать заново.

Я использую EF Core 2.1

Это было мое первоначальное определение модели.

public class Customer //Parent
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Email { get; set; }

    public BankAccount BankAccount { get; set; }

}


public class BankAccount
{
    public int Id { get; set; }

    public string Branch { get; set; }

    public string AcntNumber { get; set; }

    public DateTime CreatedDate { get; set; }

    public int CustomerId { get; set; }

    public Customer Customer { get; set; }

}

Но я понял, что наличие Id & CustomerId обоих является накладными расходами, поскольку его отношение «один к одному», я могу обновить определение модели BankAccount, как показано ниже.

public class BankAccount
{
    public int Id { get; set; }

    public string Branch { get; set; }

    public string AcntNumber { get; set; }

    public DateTime CreatedDate { get; set; }

    public Customer Customer { get; set; }

}

В то время как в классе DbContext определена основная сущность, как показано ниже.

HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);

При запуске update-database я получаю следующую ошибку.

System.InvalidOperationException: чтобы изменить свойство IDENTITY столбца, столбец необходимо удалить и создать заново.

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


person Kgn-web    schedule 21.11.2018    source источник
comment
что вы имеете в виду под «... я понял, что наличие Id и CustomerId - это накладные расходы, поскольку их взаимно-однозначное отношение»? Id - это первичный ключ, а CustomerId - внешний ключ, так какие накладные расходы здесь?   -  person Elyas Esna    schedule 21.11.2018
comment
@ElyasEsna, One Customer One BankAccount, поэтому идентификатор в сущности «Клиент» можно использовать как FK и первичный ключ в сущности BankAccount.   -  person Kgn-web    schedule 21.11.2018
comment
похоже, проблема github.com/aspnet/EntityFrameworkCore/issues/7444, которая - нерешенная проблема в ядре EF.   -  person DevilSuichiro    schedule 21.11.2018
comment
Для будущих ответчиков: люди продолжают накапливать решения на этот вопрос, все они сводятся примерно к одному и тому же, и ни одно из них не подходит для производственной среды, которая не допускает потери данных и имеет внешние ключи к первичному ключу. Если у вас есть твердое решение, учитывающее это, опубликуйте его, в противном случае подумайте дважды, прежде чем добавлять больше шума.   -  person Gert Arnold    schedule 13.07.2021


Ответы (12)


Я столкнулся с той же проблемой, и я решил ее за два шага и две миграции:

Шаг 1

  1. Отбросьте столбец идентичности.
  2. Прокомментируйте идентификатор в BankAccount и добавьте новый (например, BankAccountId в качестве идентификатора
    , добавьте миграцию и обновление - при этом идентификатор будет удален).
  3. Добавьте новый столбец в качестве идентификатора.

Шаг 2

  1. Отбросьте только что добавленный столбец и снова добавьте предыдущий. Комментарий BankAccountId и идентификатор отказа от комментария.
  2. Добавьте миграцию и обновление (это приведет к удалению BankAccountId и добавлению идентификатора в качестве идентификатора).
person Hani    schedule 18.06.2019
comment
Работал отлично - person Mohammed A. Fadil; 22.01.2020
comment
Работает только в сверхпростом сценарии без внешних ключей. Не совсем подходящее решение. - person Gert Arnold; 26.09.2020
comment
Этого было достаточно для меня, чтобы преодолеть черту, спасибо - person csharpdudeni77; 14.01.2021

У меня возникла эта проблема, когда я попытался изменить модель с public byte Id {get; set;} на public int Id {get; set;}. Чтобы решить эту проблему, я сделал следующее:

  1. Удалите все миграции до создания целевой модели с помощью Remove-Migration -Project <target_project> в консоли диспетчера пакетов.
  2. Удалить фактическую базу данных
  3. Если у вас есть некоторые миграции в середине, которые вы не создавали (например, они пришли из другой ветки), скопируйте файлы миграции, а также файл ModelSnapshot и вставьте их в свою ветку (перезапишите их осторожно!).
  4. создать новую миграцию с add-migration <migration_name> в консоли диспетчера пакетов
  5. обновить базу данных с помощью update-database в консоли диспетчера пакетов

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

person Tito Leiva    schedule 03.04.2019
comment
Хотя эта стратегия совершенно верна, если вы работаете в среде разработки, она становится проблематичной, если вы работаете в предпроизводственной среде. - person Falk; 12.12.2019

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

  • Чтобы избежать этой ошибки, закомментируйте связанный код в файле миграции.
  • или Удалите файлы миграции и создайте новый.
  • Удалите восходящую миграцию и позвольте миграции генерировать новый код.
person Payam Khaninejad    schedule 28.03.2019

Мне пришлось:

  1. Полностью прокомментируйте таблицу из кода
  2. Запустите миграцию, которая очистит его от БД
  3. Снова раскомментируйте таблицу с исправленным отображением
  4. Запустите миграцию еще раз

Выполнено

person Bassel    schedule 26.09.2020
comment
Работает только в сверхпростом сценарии без внешних ключей. Не совсем жизнеспособное решение. - person Gert Arnold; 26.09.2020
comment
Нет, внешние ключи уже были. Вот почему возникла проблема. - person Bassel; 29.09.2020
comment
Что ты имеешь в виду? Эти 4 шага не работают с внешними ключами таблицы, которую вы отбрасываете. - person Gert Arnold; 29.09.2020

На мой взгляд, запуск EF Migrations против чего-либо, кроме вашей базы данных разработки, вызывает проблемы, поскольку вы, естественно, ограничены тем фактом, что EF-миграции иногда категорически отказываются работать при изменении структуры ваших объектов (изменение первичных ключей и изменение внешних ключей наиболее часто встречающиеся).

В течение многих лет я использовал инструменты, чтобы гарантировать, что схема БД включена в систему управления версиями (в дополнение к миграции EF). Сделайте свои разработки, чтобы изменить свою базу данных разработчиков (где данные не важны), создайте несколько миграций, но затем используйте инструменты для их объединения в сценарий развертывания БД.

Вот краткое описание того, что я бы сделал в этом случае: -

  1. Удалить (закомментировать) все ссылки на старый класс BankAccount
  2. Создать миграцию и применить к базе данных разработчиков
  3. Повторно добавьте класс BankAccount с исправленным определением.
  4. Создать миграцию и применить к базе данных разработчиков
  5. Используйте инструмент сравнения БД (я предпочитаю APEX SQL Diff, но на рынке есть и другие), чтобы создать сценарий развертывания, который объединяет обе миграции.
  6. Протестируйте этот скрипт в своей промежуточной среде (где у вас должны быть данные)
  7. Если проверка прошла успешно, подайте заявку на производство

Реальность такова, что если у вас есть производственные данные, структуру которых вы хотите радикально изменить с помощью подхода «сначала код», это, вероятно, плохо кончится для вас, если вы не поймете и не решите проблему миграции данных из одной структуры в другую.

person Cueball 6118    schedule 15.03.2020
comment
Я много лет пользовался инструментами ... - Подскажите, пожалуйста, какими инструментами вы пользовались? - person arantar; 03.04.2020
comment
ApexSQL - мой предпочтительный инструмент для сравнения как схемы БД, так и данных БД, чтобы помочь процессу развертывания. У них есть различные варианты покупки и полнофункциональная бесплатная пробная версия. У Red Gate есть аналогичное предложение под названием «Сравнение SQL». - person Cueball 6118; 06.04.2020
comment
Любой ответ (даже если команда MS Docs Team мне говорит), который сначала вращается вокруг кода с миграциями, предназначен для студенческих проектов и учебных пособий. В реальном мире с живыми инстансами БД это ужасная шутка. То, что @ Cueball6118 ответил выше, является реальным ответом (используете ли вы Apex и т. Д., Visual Studio DB Comparison или просто сценарии SQL). Мы поддерживаем экземпляры Live DB (MSSQL) и советуем новичкам отучиться от этих практических занятий, чтобы избежать бессонных ночей на работе. Даже идеально выглядящая миграция может привести к недопустимому простою в реальных средах. - person Ajay; 19.04.2021

В моем случае таблица SharedBalances переименована в Balances, а ее идентификационный столбец SharedBalancesId переименован в BalanceId. Команды SQL выполняются на SQL Server. Вы также можете попробовать migrationBuilder.Sql (my_sql_command_here)

Я создал миграцию и получил ту же ошибку.

Переименуйте столбец и таблицу с помощью команды TSQL:

EXEC sp_RENAME 'SharedBalances.SharedBalanceId', 'BalanceId', 'COLUMN';

EXEC sp_RENAME 'SharedBalances', 'Balances';

-- Caution: Changing any part of an object name could break scripts and stored procedures.

Прокомментируйте команду RenameTable в переносе:

/*
migrationBuilder.RenameTable(
    name: "SharedBalances",
    newName: "Balances");
*/

Прокомментируйте команду AddPrimaryKey в переносе:

/*
migrationBuilder.DropPrimaryKey(
    name: "PK_SharedBalances",
    table: "Balances");
migrationBuilder.AddPrimaryKey(
    name: "PK_Balances",
    table: "Balances",
    column: "BalanceId");
*/

Обновите случаи использования команд DropForeignKey имени таблицы в процессе миграции:

Из этого....

        migrationBuilder.DropForeignKey(
            name: "FK_SharedBalances_Users_OwnerUserId",
            table: "SharedBalances");

        migrationBuilder.DropPrimaryKey(
            name: "PK_SharedBalances",
            table: "SharedBalances");

К этому:

        migrationBuilder.DropForeignKey(
            name: "FK_SharedBalances_Users_OwnerUserId",
            table: "Balances");

        migrationBuilder.DropPrimaryKey(
            name: "PK_SharedBalances",
            table: "Balances");

Теперь ваша миграция будет работать. Вот как это произошло:

person profimedica    schedule 24.01.2021

Вопрос состоит из двух частей:

TL; DR: Пусть EF сделает это за вас.

Во-первых: пусть EF выполняет отношения

Короче говоря, свойство идентификации - это то, что БД использует для управления выделенным столбцом идентификатора, поэтому он не зависит от чего-либо внешнего для идентификации каждой строки, поэтому класс bankAccount нуждается в собственном поле идентификатора, чтобы иметь свойство идентификации; теперь, если вы попытаетесь указать EF вручную, как делать отношения, как вы делаете с строкой

    HasOne(b => b.Customer).WithOne(c => c.BankAccount).HasForeignKey<BankAccount>(f => f.Id);

то, что вы делаете, - это переопределение внутренней логики самого EF, и в этом случае вы сообщаете EF, что идентификатор банковского счета - это поле, которое ссылается на клиента, что не так, и поэтому EF пытается удалить IDENTITY из поле id в модели банковского счета, но это только потому, что вы сказали ему, что идентификатор банковского счета должен совпадать с идентификатором клиента. Думаю, я понимаю, что вы пытаетесь сказать об отношениях «один к одному», но что происходит, когда клиент пытается открыть другой банковский счет? D: Вместо этого вы должны сохранить поле int CustomerId и удалить поле Customer Customer не только потому, что оно чище, но и потому, что EF распознает связь между ними, пока существует класс с именем Customer с полем Id.

   public int CustomerId { get; set; } //keep

   public Customer Customer { get; set; } //delete

Таким образом, клиент может открыть столько счетов в банке, сколько ему заблагорассудится, стол не пострадает, и EF знает, что делать.

Он автоматически сгенерирует соответствующий внешний ключ и добавит его в файл миграции следующим образом:

    migrationBuilder.AddForeignKey(
            name: "FK_BankAccount_Customer_CustomerId",
            table: "BankAccount",
            column: "CustomerId",
            principalTable: "Customer",
            principalColumn: "Id",
            onDelete: ReferentialAction.Cascade);

Это будет отражать отношение «один ко многим», и это нормально.

Теперь, чтобы ответить на вопрос, хотите ли вы все еще отбросить свойство:

Во-вторых: заставить EF удалить свойство Identity

(но это не решит проблему внешнего ключа исходного вопроса).

Во-первых, просто напомним: чтобы изменить свойство идентификации, менеджер БД (mysql, sqlserver и т. Д.) Всегда будет просить вас удалить и воссоздать таблицу, потому что это поле является сердцем таблицы. Поэтому вам нужно обмануть EF, чтобы он нашел обходной путь.

  1. Добавьте второй элемент Id в класс модели с очевидным именем, например duplicateId.

    public class BankAccount
    {
        public int Id { get; set; }
        public int duplicateId { get; set; }
        ...
    }
    
  2. ЭТО УЮЛКА;)
    В классе, в котором вы реализовали интерфейс DbContext, добавьте следующий метод, в котором вы указываете ef, какое поле вы хотите использовать в качестве первичного ключа:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<BankAccount>().HasKey(x => new { x.duplicateId });
    }
    
  3. Добавьте новую миграцию с $ dotnet ef migrations add ModelIdChange1, поскольку при этом изменяется первичный ключ таблицы, и метод миграции Up должен выглядеть примерно так:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropPrimaryKey(
            name: "PK_BankAccount",
            table: "BankAccountTableName");
    
        migrationBuilder.AddColumn<int>(
            name: "duplicateId",
            table: "BankAccountTableName",
            type: "int",
            nullable: false,
            defaultValue: 0)
            .Annotation("SqlServer:Identity", "1, 1");
    
        migrationBuilder.AddPrimaryKey(
            name: "PK_BankAccount",
            table: "BankAccountTableName",
            column: "duplicateId");
    ...
    }
    
  4. Затем выполните обновление базы данных с помощью $ dotnet ef database update (эти команды могут отличаться, используйте любой синтаксис, который вы уже использовали ранее).

  5. (НЕОБЯЗАТЕЛЬНО) Если вам нужно сохранить исходные идентификаторы, убедитесь, что они сохранились, или просто выполните «грязное» обновление таблицы, чтобы скопировать данные из поля Id в duplicateId.

  6. Теперь исходное поле Id можно удалить или обновить, поэтому просто удалите исходное поле из модели:

    public class BankAccount
    {
        public int duplicateId { get; set; }
        ...
    }
    

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

  1. И добавьте новую миграцию с $ dotnet ef migrations add ModelIdChange2, а затем выполните обновление базы данных с $ dotnet ef database update, которое удалит исходный столбец Id и оставит duplicateId в качестве первичного ключа.

  2. Теперь модель выглядит почти как исходная, но с новым столбцом идентификаторов вы можете оставить это так или просто переименовать поле обратно с duplicateId на Id в классе BankAccount следующим образом:

    public class BankAccount
    {
        public int Id { get; set; }
        ...
    }
    

    и выполните $ dotnet ef migrations add ModelIdChange3, а затем выполните обновление базы данных с помощью $ dotnet ef database update.

person unJordi    schedule 21.05.2021

  1. В таблице нет важных данных
  • Переименовать таблицу entity.ToTable("BankAccount2")
  • Добавить Выполнить миграцию Add-Migration BankAccountTempChanges
  • Обновите базу данных Update-Database
  • Переименовать таблицу обратно entity.ToTable("BankAccount")
  • Добавить Выполнить миграцию Add-Migration BankAccountOk
  • Снова обновите базу данных Update-Database
  1. В таблице есть данные, которые нельзя потерять
  • Применить решение из ответа @Hani
person Bellash    schedule 12.07.2021

пожалуйста, выполните этот шаг:

1-пожалуйста, сделайте все изменения столбца идентификатора на сервере sql (не в вашей структуре первого объекта кода)

2 комментария изменения столбца идентификаторов в миграции (файл .cs)

3-обновление-база данных

наслаждайся этим

person Ali Rasouli    schedule 23.02.2021

Я столкнулся с той же проблемой (в моем случае у меня не было данных в таблицах), и я решил ее таким образом (это не правильный способ, но у меня это сработало):

  1. Я удалил вручную миграции из проекта EFCore. Я удалил те строки, которые были добавлены из файла _ContextModelSnapshot. (У меня была одна миграция, которая была применена, и одна, которая была создана, но не применялась, так как я получал сообщение об ошибке - Измените свойство IDENTITY столбца, столбец необходимо удалить и воссоздать )
  2. Я вручную удалил таблицы, которые были созданы в базе данных (при первой миграции)
  3. Я удалил строку в таблице _EFMigrationHistory, которая связана с миграцией, которую я хотел удалить.
  4. Повторно запустить VS
  5. Добавить-Migration NewOneCleanMigration
  6. Обновление базы данных
person K.Nikolic    schedule 07.04.2021

Для таких ленивых, как я: вы хотите изменить тип данных столбца первичного ключа Id с int на Guid в таблице с именем < strong> Переводы, как и в моем случае.

  1. Ваша сгенерированная миграция в этом случае
migrationBuilder.AlterColumn<Guid>(
     name: "Id",
     table: "Translations",
     type: "uniqueidentifier",
     nullable: false,
     oldClrType: typeof(int),
     oldType: "int")
     OldAnnotation("SqlServer:Identity", "1, 1");

Вы можете удалить это или закомментировать

  1. Из ошибки обновления базы данных System.InvalidOperationException: чтобы изменить свойство IDENTITY столбца, столбец необходимо удалить и создать заново.
  2. Мы также знаем, что мы не можем удалить столбец, не сняв сначала ограничение первичного ключа. Наша новая миграция становится
migrationBuilder.DropPrimaryKey(
    name: "PK_Translations",
    table: "Translations");
  migrationBuilder.DropColumn(
    name: "Id",
    table: "Translations");
  migrationBuilder.AddColumn<Guid>(
    name: "Id",
    table: "Translations",
    type: "uniqueidentifier",
    nullable: false);

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

person Brainykat Boss    schedule 03.06.2021
comment
Как это отвечает на вопрос? - person Gert Arnold; 03.06.2021

У меня была аналогичная проблема, когда я менял компонент реляционной навигации в конфигурации таблицы с WithMany на WithRequiredDependent. Платформа Entity хотела удалить индекс и воссоздать столбец, хотя в базе данных ничего не должно было измениться.

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

person nightwuffle    schedule 16.06.2021