13

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

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

4

6 回答 6

8

取决于您使用的 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()
        {
            ........
        }
于 2012-12-12T07:47:59.407 回答
4

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

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

于 2012-12-12T08:01:49.110 回答
2

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

update-database -Verbose

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

marvc1 的回答

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

于 2012-12-12T08:48:47.607 回答
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';");

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

于 2018-06-22T11:45:24.943 回答
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; }

    ....
    }

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

于 2019-02-20T00:11:57.920 回答
0

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

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

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

  3. 删除旧文件

这对我有用

于 2021-04-26T16:32:38.570 回答