我有这样一个场景,我想在一个实体来更改主键的名称,并能够运行更新数据库-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冲突与孩子实体类。
我如何能成功做到这一点任何想法?
依赖于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当你在运行程序包管理器控制台,一个新的文件(*的.cs)“添加迁移AddBlogUrl”命令创建。
与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()
{
........
}
双方marvc1和emanyalpsid与建议摆弄之后。 我决定只删除数据库并再次创建它。 这是通过简单地在服务器资源管理器删除数据库中VS2012,也确保程序App_Data下的.mdf文件也被删除完成。 .mdf文件通常是隐藏的,看到它略低于上显示所有文件的解决方案资源管理器工具栏上点击一下,你会看到它。 当这些步骤完成后,只需运行在包管理器控制台下面的代码:
update-database -Verbose
-verbose只是让你确认你所创造的东西。
marvc1的回答:
工作得很好,只是它不更改数据库中的名字,如果你不是太担心数据库的名称,它是去做最安全的方式。 通过在数据库中,我的意思是名称, In the entity Team, Id would still be Id and not TeamId
最简单的解决方案是不重命名数据库中的主键,而不是你的类映射到您的主键,并给它任何你想要的名称。 像这样:
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; }
}
就个人而言,我会保持类名作为标识。 命名约定[表名+编号]是一个主键,老学校,矫枉过正(对于外键是好的)。 对我来说,只是增加了噪音,你的代码行。 team.TeamId
没有比好team.Id
。
用户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';");
注意,老名应该是完全的名字,但新名字应该是短。 否则,就不会正确工作
我有@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.在类中列重命名为这个名字,这一步重命名你的项目中科拉姆了。
注意:你并不需要的关键属性,在EF知道ID关键字是主键。
public class Team
{
[HiddenInput(DisplayValue = false)]
public virtual int ID { get; set; }
....
}
你不需要添加迁移,因为最后的更改不会影响数据库。