Ach*_*khi 4 ef-migrations entity-framework-4.3
我正在使用EF 4.3.1迁移,我有Configuration类,其中我有以下代码:
internal sealed class Configuration : DbMigrationsConfiguration<DbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
protected override void Seed(PayByPhoneDbContext context)
{
context.Roles.AddOrUpdate(r => r.Name, new Role { Name = "A" }, new Role { Name = "B" });
context.Administrators.AddOrUpdate(a => a.Email, new Administrator { Email = "a@a.com" Name = "A", Role = context.Roles.Local.SingleOrDefault(role => role.Name == "A") });
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当我不存在数据库时运行migrate命令(MSBuild脚本的一部分)时,将创建表并按预期进行种子设定.但是当我在现有数据库上运行migrate命令而没有任何迁移并且所有数据都已经播种时(当需要更新而不是插入时),我在运行migrate命令时出错:
没有待定的显式迁移.
运行种子方法.
System.Data.Entity.Infrastructure.DbUpdateException:更新条目时发生错误.有关详细信息,请参阅内部异常 ---> System.Data.UpdateException:更新条目时发生错误.有关详细信息,请参阅内部异常 ---> System.Data.SqlClient.SqlException:UPDATE语句与FOREIGN KEY约束"FK_Administrators_Roles_RoleId"冲突.冲突发生在数据库"xxxDB",表"dbo.Roles",列"Id"中.
该语句已终止.
堆栈跟踪:
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at System.Data.Mapping.Update.Internal.DynamicUpdateCommand.Execute(UpdateTranslator translator, EntityConnection connection, Dictionary`2 identifierValues, List`1 generatedValues)
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
--- End of inner exception stack trace ---
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
--- End of inner exception stack trace ---
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at System.Data.Entity.Migrations.DbMigrator.SeedDatabase()
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.SeedDatabase()
at System.Data.Entity.Migrations.DbMigrator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.Infrastructure.MigratorLoggingDecorator.Upgrade(IEnumerable`1 pendingMigrations, String targetMigrationId, String lastMigrationId)
at System.Data.Entity.Migrations.DbMigrator.Update(String targetMigration)
at System.Data.Entity.Migrations.Infrastructure.MigratorBase.Update(String targetMigration)
at System.Data.Entity.Migrations.Design.ToolingFacade.UpdateRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
Run Code Online (Sandbox Code Playgroud)
运行SQL Server探查器我发现执行时发生错误:
exec sp_executesql N'update [dbo].[Administrators]
set [RoleId] = @0
where ([Id] = @1)
',N'@0 int,@1 bigint',@0=0,@1=1
Run Code Online (Sandbox Code Playgroud)
在Seed方法中使用外键对数据进行种子的正确方法是什么?
AddOrUpdate会将未指定的列重置为null(如果是int,则为零).
我的理解是这种行为(顺便说一句可怕)不适用于它被识别为键或自动增量的列,但显然它就是你的情况.
我的建议是检查以确保数据库中不存在该角色,然后执行标准add()(如果不存在).
我为所有种子数据执行此操作,因为您永远不知道以后何时可以提供用于更新所播种数据的界面,并且您不希望Seed()方法在这些情况下覆盖您的更改.
另请注意,如果您选择使用MigrateDatabaseToLatestVersion数据库初始化程序,则每次应用程序重新启动时都会触发Seed()(dll部署,web.config更新等).
最好在Seed()方法中进行防御性编码.