Как изменить имя первичного ключа в EF Code First?

У меня есть сценарий, в котором я хотел бы изменить имя первичного ключа в сущности и иметь возможность запускать update-database -force. См. Ниже, когда код и ошибка возникают, когда я пытаюсь.

Сущность:

public class Team
{
    [Key]
    [HiddenInput(DisplayValue = false)]
    public virtual int Id { get; set; }

    [Display(Name = "Full Name:")]
    public virtual string Name { get; set; }
}

Объект изменен:

public class Team
{
    [Key]
    [HiddenInput(DisplayValue = false)]
    public virtual int TeamId { get; set; }

    [Display(Name = "Full Name:")]
    public virtual string Name { get; set; }
}

Когда я запустил Update-database -Force, я получаю следующую ошибку.

Multiple identity columns specified for table 'Teams'. Only one identity column per table is allowed.

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

Любые идеи о том, как я могу сделать это успешно?

Ответ 1

Зависит от используемой вами версии EF. В результате миграции вы увидите следующее:

"drop column Id" и "добавить столбец TeamId".

С этим вы потеряете все значения и "дочерние соединения"...

Единственное "безопасное" решение, которое я вижу на данном этапе, - это сочетание Migrations и "ручных операций SQL".

Решение EASY:

1- принимая во внимание, что у вас уже есть "базовая" миграция, создающая таблицу с идентификатором, теперь создайте новую миграцию с помощью "обновления". Теперь НЕ запускайте его.

2- Откройте этот файл и напишите новую строку перед созданными строками и используйте команду SQL, примерно так:

     SQL("ALTER TABLE table_name RENAME COLUMN old_name to new_name;");

Это изменит имя ДО того, как перенос удалит столбец и создаст новый, произойдет следующее: вы измените имя перед удалением, затем будет выполнено удаление, но оно будет "сбой", но это ничего не повредит,

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

ОБНОВЛЕНО ОТВЕТЫ # 1

Когда я говорю о миграции объектов Entity Framework, я имею в виду следующее: http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx Когда вы запускаете команду Add-Migration AddBlogUrl в консоли диспетчера пакетов, создается новый файл (*.cs).

Пример файла миграции файла с командами SQL:

public partial class AddAbsencesTypesAndCategories : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "pvw_AbsenceType",
                c => new
                    {
                        Id = c.Int(nullable: false, identity: true),
                        Name = c.String(nullable: false),
                        CountAsVacation = c.Boolean(nullable: false),
                        IsIncremental = c.Boolean(nullable: false),
                    })
                .PrimaryKey(t => t.Id);

          .....

            AddColumn("pvw_Absence", "CategoryId", c => c.Int(nullable: false));
                        AddForeignKey("pvw_Absence", "StatusId", "pvw_AbsenceStatusType", "Id");
            AddForeignKey("pvw_Absence", "CategoryId", "pvw_AbsenceType", "Id");
            CreateIndex("pvw_Absence", "StatusId");
            CreateIndex("pvw_Absence", "CategoryId");
            DropColumn("pvw_Absence", "MainCategoryId");
            DropColumn("pvw_Absence", "SubCategoryId");
           ......
            Sql(@"
                                        SET IDENTITY_INSERT [dbo].[pvw_AbsenceStatusType] ON
                    INSERT pvw_AbsenceStatusType (Id, Name) VALUES (1, N'Entwurf')                       
                                        SET IDENTITY_INSERT [dbo].[pvw_AbsenceStatusType] OFF
            ");    
            .....
        }

        public override void Down()
        {
            ........
        }

Ответ 2

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

public class Team
{
    [Key]
    [HiddenInput(DisplayValue = false)]
    [Column("Id")] //this attribute maps TeamId to the column Id in the database
    public virtual int TeamId { get; set; }

    [Display(Name = "Full Name:")]
    public virtual string Name { get; set; }
}

Лично я бы сохранил имя класса как Id. Соглашение об именах [TableName + Id] - это старая школа и overkill для первичного ключа (для внешнего ключа это хорошо). Для меня это просто добавляет шум в ваши строки кода. team.TeamId не лучше team.Id.

Ответ 3

После возиться с предложением как marvc1, так и emanyalpsid. Я решил просто отбросить базу данных и создать ее снова. Это делается просто удалением базы данных в Server Explorer в VS2012, а также убедитесь, что файл .mdf в App_Data также удален. Файл .mdf обычно скрыт, чтобы увидеть его только в панели инструментов Solution Explorer, нажмите "Показать все файлы", и вы увидите его. когда эти шаги будут выполнены, просто запустите приведенный ниже код в консоли диспетчера пакетов:

update-database -Verbose

-Verbose просто позволяет вам проверить, что вы создаете.

marvc1 Ответ

Работает отлично, за исключением того, что он не изменяет имена в базе данных, если вы не слишком беспокоитесь о именах баз данных, это самый безопасный способ сделать это. По именам в базе данных я имею в виду In the entity Team, Id would still be Id and not TeamId