【问题标题】:How to Change the name of a primary key in EF Code First?如何在 EF Code First 中更改主键的名称?
【发布时间】:2012-12-12 07:16:26
【问题描述】:

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

关于我如何成功地做到这一点的任何想法?

【问题讨论】:

  • 您可以使用 [Column("Id")] 属性将 TeamId 映射到主键 Id,或者是否需要将列名和 POCO 变量都命名为 TeamId?
  • @marvc1 我正在尝试你的建议,我会在一分钟内通知你
  • @marvc1 嘿伙计,你的建议似乎奏效了,我看到你在下面给出了答案。

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


【解决方案1】:

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

“删除列 ID”和“添加列 TeamId”。

这样你会失去所有的价值和“子连接”......

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

简单的解决方案:

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 当您在包管理器控制台中运行“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 中,当您说打开该文件时,您指的是什么文件?正常情况下,我会在 SQL Server Management Studio 中运行该 SQL 语句,但它似乎找不到我想要的数据库。
  • 当我谈到实体框架迁移时,我指的是:blogs.msdn.com/b/adonet/archive/2012/02/09/… 当您在包管理器控制台中运行“Add-Migration AddBlogUrl”命令时,会创建一个新文件 (*.cs) .
  • 不确定 EF5 是否会创建此文件,因为我找不到,除非我应该自己创建它。 EF5 在 Migration 文件夹中创建一个 Configuration.cs。这个文件有一个内部密封类,它有它的 pconstructor 和一个种子方法。
  • @KomengeMwandila 谢谢 :)
【解决方案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 好。

【讨论】:

  • 只有当您不关心数据库中的名称时,这才是一个不错的解决方案。
  • @emanyalpsid 这就是我现在担心的问题,代码运行成功,但数据库中的名称与以前一样,不确定我是否喜欢这个想法。我现在正在考虑删除数据库并重新创建它,除了启用代码优先迁移之外,应该不会花很长时间。
  • 如果您不担心数据库中的数据,那么只需将其删除并重新创建即可。
  • @marvc1 现在这样做,与浪费更多时间尝试更便宜的方法相比,做更多的数据输入并没有什么坏处。您的建议虽然有效,但不是我想要的方式。
  • 您始终可以使用种子方法创建示例数据,然后每次删除数据库时都不必手动重新创建它。
【解决方案3】:

在修改了 marvc1 和 emanyalpsid 的建议之后。我决定只删除数据库并重新创建它。这是通过简单地删除VS2012中服务器资源管理器下的数据库来完成的,并确保App_Data下的.mdf文件也被删除。 .mdf 文件通常是隐藏的,要在“解决方案资源管理器”工具栏下单击“显示所有文件”即可看到它,您将看到它。完成这些步骤后,只需在包管理器控制台中运行以下代码:

update-database -Verbose

-Verbose 只是让您验证您正在创建的内容。

ma​​rvc1 的回答

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

【讨论】:

    【解决方案4】:

    用户 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';");
    

    注意,旧名称应该是全名,而新名称应该是简短的。否则会出错

    【讨论】:

      【解决方案5】:

      我有一个基于@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; }
      
          ....
          }
      

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

      【讨论】:

        【解决方案6】:

        您可以分 3 步完成此操作

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

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

        3. 删除旧文件

        这对我有用

        【讨论】:

          猜你喜欢
          • 2012-11-16
          • 1970-01-01
          • 1970-01-01
          • 2011-07-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多