如何在EF Code First中更改主键的名称?

问题描述 投票:12回答:5

我有一个场景,我想更改实体中的主键名称,并能够运行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与子实体类冲突。

关于我如何成功完成任何想法?

c# entity-framework-5 ef-migrations
5个回答
6
投票

取决于您使用的EF版本。即使迁移,您将看到的结果如下:

“drop column Id”和“add column TeamId”。

有了这个,你将失去所有的价值观和“儿童联系”......

我在这一点上看到的唯一“安全”解决方案是迁移和“手动SQL操作”的混合。

EASY解决方案:

1-考虑到您已经创建了具有ID的表的“基础”迁移,现在使用“更新”创建新的迁移。现在不要运行它。

2-打开该文件并在生成的行之前写一个新行并使用SQL命令,如下所示:

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

这将更改名称在迁移删除列并创建新列之前,将会发生的事情是:在删除之前更改名称,然后执行删除但它将“失败”但不会造成任何损害。

但现在你问:为什么我这样做?好吧,如果你使用迁移,即使你删除行删除列并创建一个新的,下次你自动创建一个新的迁移文件时,这些新的行将在那里......这就是原因。

更新的答案#1

当我谈到实体框架迁移时,我指的是:http://blogs.msdn.com/b/adonet/archive/2012/02/09/ef-4-3-code-based-migrations-walkthrough.aspx当您在软件包管理器控制台中运行“添加 - 迁移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()
        {
            ........
        }

3
投票

最简单的解决方案是不重命名数据库中的主键,而是将您的类映射到主键并为其指定任何名称。像这样:

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]是旧学校并且对于主键是过分的(对于外键来说它是好的)。对我来说,这只会给你的代码行增加噪音。 team.TeamId并不比team.Id好。


2
投票

在摆弄了marvc1和emanyalpsid的建议之后。我决定放弃数据库并再次创建它。这是通过简单地删除VS2012中的服务器资源管理器下的数据库来完成的,并确保也删除了App_Data下的.mdf文件。 .mdf文件通常是隐藏的,只需在解决方案资源管理器工具栏下单击“显示所有文件”,您就会看到它。完成这些步骤后,只需在Package Manager Console中运行以下代码:

update-database -Verbose

-Verbose只是让你验证你正在创建什么。

marvc1的答案

工作得很好,除了它不会改变数据库中的名称,如果你不太担心数据库名称,这是最安全的方法。通过数据库中的名字,我的意思是,In the entity Team, Id would still be Id and not TeamId


0
投票

用户Dryadwoods建议在迁移中执行以下sql:

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

但是:

使用MS SQL Server中的ALTER TABLE语句无法重命名列。请改用sp_rename。

所以,我将其更改为以下代码:

Sql("exec sp_rename 'dbo.Batches.BatchNo', 'Id', N'COLUMN';");

注意,那个旧名称应该是全名,但新名称应该简短。否则它将无法正常工作


0
投票

我有一个很好的解决方案基于@Marvin Rounce解决方案。此解决方案非常容易应用类和数据库的更改。

1.映射您的类,此步骤仅在数据库中重命名该列。

public class Team

 {
        [Key]
        [HiddenInput(DisplayValue = false)]
        [Column("ID")] 
        public virtual int TeamId { get; set; }
    ....
    }

2.在程序包管理器控制台中添加迁移。

PM> Add-Migration rename_TeamID

3.更新数据库。

PM> update-database

4.将类中的列重命名为此名称,此步骤也重命名项目中的列。

注意:您不需要key属性,EF知道ID关键字是主键。

public class Team
        {

       [HiddenInput(DisplayValue = false)]
       public virtual int ID { get; set; }

    ....
    }

您不需要添加迁移,因为上次更改不会影响数据库。

© www.soinside.com 2019 - 2024. All rights reserved.