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

时间:2012-12-12 07:16:26

标签: c# entity-framework-5 ef-migrations

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

有关如何成功完成此任务的任何想法?

6 个答案:

答案 0 :(得分:6)

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

"删除列ID"和"添加列TeamId"。

有了这个,你将失去所有价值观和儿童关系" ......

唯一的"安全"我现在看到的解决方案是迁移和#34;手工操作"。

EASY解决方案:

1-考虑到您已经拥有" base"使用ID创建表的迁移现在使用" update"创建新的迁移。现在不要运行它。

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()
        {
            ........
        }

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

答案 2 :(得分: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

答案 3 :(得分:0)

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

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

但是:

  

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

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

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

请注意,旧名称应为全名,而新名称应简短。否则它将无法正常工作

答案 4 :(得分:0)

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

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

public class Team

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

2。。在Package Manager控制台中添加迁移。

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; }

    ....
    }

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

答案 5 :(得分:0)

您可以通过 3 个步骤完成此操作

  1. 添加具有新名称的字段(在本例中为 TeamId)并运行程序。将添加新字段

  2. 将 [key] 数据注释从旧字段移动到新字段并再次运行。新字段(TeamId)将是主键。

  3. 删除旧文件

这对我有用