Entity Framework Code First Migrations: значение первичного ключа
У меня есть таблица, в которой хранятся некоторые дополнительные данные для некоторых строк таблицы, например:
public class QuoteExtra
{
[Key]
public int QuoteId { get; set; }
// More fields here
}
Я хотел бы иметь возможность добавлять строки в эту таблицу, где я явно устанавливаю PK.
Если я просто оставлю его, как указано выше, установка значения и отправка строки приводит к тому, что значение будет отброшено и заменено автоматически генерируемым значением из базы данных (а столбец определяется как столбец "Идентификатор" в фактической схеме).
Это кажется правильным решением:
public class QuoteExtra
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int QuoteId { get; set; }
// More fields here
}
Однако это вместо меня вызывает исключение:
Невозможно вставить явное значение для столбца идентификатора в таблице "EnumTest", если для параметра IDENTITY_INSERT установлено значение OFF.
Итак, как мне написать свой класс, чтобы я мог установить значение Первичного ключа в EF?
Edit:
Я попытался добавить следующую миграцию на основе кода, чтобы установить IDENTITY_INSERT в ON:
public override void Up()
{
Sql("SET IDENTITY_INSERT QuoteExtra ON");
}
Я запустил его и снова попытался, но получил то же исключение, что и выше. Какая странная база данных отражает этот параметр, а работа с SQL против него напрямую позволяет мне вставлять произвольные значения для первичного ключа, поэтому казалось бы, что Entity Framework сама применяет это правило и не обращает внимания на то, что IDENTITY_INSERT не находится в факт отключен. Нужно ли устанавливать его где-нибудь в самом EF?
Изменить 2:
Я неправильно понял IDENTITY_INSERT; Я предположил, что он однажды установил его для этой таблицы на неопределенный срок. Фактически, он живет до тех пор, пока "Сессия", что означает, что, например, установка в Migration означает, что она живет... до тех пор, пока эта миграция работает, и не имеет отношения к будущим соединениям, таким как мой позже .Add() с EF, что объясняет, почему я до сих пор получил это исключение - БД действительно является источником исключения, а не EF. Поскольку IDENTITY_INSERT ограничен не более чем одной таблицей за сеанс, это довольно неэффективный способ сделать это - не создание столбца Identity PK в первую очередь похоже на лучший маршрут.
Ответы
Ответ 1
Это правильный способ создания ПК без использования автоопределения Identity:
public class QuoteExtra
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int QuoteId { get; set; }
// More fields here
}
Однако, если вы добавите DatabaseGenerated (DatabaseGeneratedOption.None)] после того, как EF Migrations уже создал таблицу, она спокойно ничего не делает для таблицы. Если это ваш сценарий, вам нужно добавить ручную миграцию, чтобы удалить таблицу:
add-migration RecreateQuoteExtra
И в процессе миграции:
public override void Up()
{
DropTable("QuoteExtra");
}
EF Автоматические миграции затем автоматически воссоздают таблицу без ограничения Identity, которая затем позволит вам установить значение PK в любое время без необходимости запуска каких-либо специальных команд, таких как IDENTITY_INSERT ON.
Похоже, что в EF7 ( "Движение данных" ) это менее разрушительный способ, или вы можете написать много ручного sql самостоятельно в процессе миграции, чтобы создавать временные таблицы и перемещать данные, если вы хотите избежать потеря существующих данных в таблице.
EDIT: в зависимости от вашего сценария EF Migrations не может воссоздать таблицу - если класс уже существует и уже добавлен в ваш DbContext, он просто опустит его и оставьте на нем, то есть ваша миграция вручную должна не только упасть, но и также создайте таблицу. Не так уж много, поскольку код EF Migrations, созданный для вас из add-migration, создаст эти инструкции для вас, но для проверки проблем потребуется немного больше кода.
Ответ 2
Это правильное решение, но только для новой таблицы. Если вы измените параметр сгенерированной базы данных для существующей таблицы, миграции EF не смогут выполнить это изменение, а столбец QuoteId
по-прежнему помечен как Identity
в базе данных.
Ответ 3
Я не мог решить эту проблему с вашими подсказками, тогда я попытался воссоздать всю базу данных, но она тоже не работала.
Чтобы исправить это, вам нужно удалить свойство identity: true при первом (!) создании столбца (например, Initial-Migration).
Может быть, это поможет кому-то..