我有一个场景,我想更改实体中的主键名称,并能够运行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,简单地说就是与子实体类冲突。
有关如何成功完成此任务的任何想法?
答案 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 个步骤完成此操作
添加具有新名称的字段(在本例中为 TeamId)并运行程序。将添加新字段
将 [key] 数据注释从旧字段移动到新字段并再次运行。新字段(TeamId)将是主键。
删除旧文件
这对我有用