entity framework代码首先AddOrUpdate方法插入重复值
我有一个简单的实体:
public class Hall { [Key] public int Id {get; set;} public string Name [get; set;} }
然后在Seed
方法中使用AddOrUpdate
来填充表:
var hall1 = new Hall { Name = "French" }; var hall2 = new Hall { Name = "German" }; var hall3 = new Hall { Name = "Japanese" }; context.Halls.AddOrUpdate( h => h.Name, hall1, hall2, hall3 );
然后我运行包pipe理控制台:
Add-Migration Current Update-Database
一切都好:我在桌子“大厅”里有三排。 但是如果我再次运行包pipe理控制台Update-Database
,我已经有五行:
Id Name 1 French 2 Japaneese 3 German 4 French 5 Japanese
为什么? 我认为应该是三排,而不是五排。 我试图使用Id
属性而不是Name
但它没有区别。
更新:
这段代码产生相同的结果:
var hall1 = new Hall { Id = 1, Name = "French" }; var hall2 = new Hall { Id = 2, Name = "German" }; var hall3 = new Hall { Id = 3, Name = "Japanese" }; context.Halls.AddOrUpdate( h => h.Id, hall1); context.Halls.AddOrUpdate( h => h.Id, hall2); context.Halls.AddOrUpdate( h => h.Id, hall3);
另外我有通过nuget安装的最新的EntityFramework。
好的,我用这个敲了一个小时的键盘。 如果你的表的Id字段是标识字段,那么它将无法工作,所以使用一个不同的标识符expression。 我使用了Name属性,并new Hall {...}
初始化程序中删除了Id字段。
这对OPs代码的调整为我工作,所以我希望它可以帮助某人:
protected override void Seed(HallContext context) { context.Halls.AddOrUpdate( h => h.Name, // Use Name (or some other unique field) instead of Id new Hall { Name = "Hall 1" }, new Hall { Name = "Hall 2" }); context.SaveChanges(); }
此代码工作:
public Configuration() { AutomaticMigrationsEnabled = true; } protected override void Seed(HallContext context) { context.Halls.AddOrUpdate( h => h.Id, new Hall { Id = 1, Name = "Hall 1" }, new Hall { Id = 2, Name = "Hall 2" }); context.SaveChanges(); }
我知道这是一个老问题,但是正确的答案是,如果你自己设置了id#并且想要使用AddOrUpdate,那么你需要告诉EF / SQL你不想让它生成ID#。
modelBuilder.Entity<MyClass>().Property(p => p.Id) .HasDatabaseGeneratedOption(System.ComponentModel .DataAnnotations.Schema.DatabaseGeneratedOption.None);
这样做的缺点是,当你插入一个新的项目,你需要设置它的ID,所以如果这是在运行时dynamic(而不是从种子数据)完成,那么你将需要计算出下一个ID。 Context.MyClasses.Max(c=>c.Id) + 1
效果很好。
如果您错误地设置实体状态,也可能导致这种情况。 当我运行update-database时,我不断收到以下错误…“Sequence包含多个匹配的元素。
例如,我在每个update-database命令上创build了重复的行(这当然不是在种子数据时发生的),然后下一个update-database命令根本不起作用,因为它发现了多个匹配(因此序列错误说我有多个匹配的行)。 这是因为我已经覆盖SaveChanges在我的上下文文件与方法调用ApplyStateChanges …
public override int SaveChanges() { this.ApplyStateChanges(); return base.SaveChanges(); }
我正在使用ApplyStateChanges来确保添加对象图时,Entity Framework明确知道对象是否处于已添加或已修改状态。 关于如何使用ApplyStateChanges的完整说明可以在这里find。
这个工程很好(但要注意!!)…如果你也使用CodeFirst迁移种子数据库,那么上面的方法将导致Seed方法中AddOrUpdate()调用的破坏。 因此,在任何其他事情之前,只要检查你的DBContext文件,并确保你没有覆盖SaveChanges在上面的方式,或者你会最终得到重复的数据运行update-database命令第二次,然后将无法第三次,因为每个匹配项目有多于一行。
当涉及到它的时候,你不需要在AddOrUpdate()中configurationId,这就违背了简单和初始数据库播种的全部目的。 它可以正常工作,例如:
context.Students.AddOrUpdate( p => p.StudentName, new Student { StudentName = "Bill Peters" }, new Student { StudentName = "Jandra Nancy" }, new Student { StudentName = "Rowan Miller" }, new Student { StudentName = "James O'Dalley" },
只是很长,因为我没有覆盖SaveChanges方法在我的上下文文件与调用ApplyStateChanges。 希望这可以帮助。
我发现AddOrUpdate
可以正常使用不是ID的字段。 如果这对你context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)
: context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)
您可能想要使用“French_test_abc_100”,“German_test_abc_100”等Hall名称
当您testing您的应用程序时,这会阻止硬编码的testing数据。
如果对象(大厅)的ID是0,它是一个插入。 我想你需要仔细检查你的大厅物品的ID字段
您的ID字段是身份字段吗? 我遇到了同样的问题。 当我从我的ID字段中删除身份状态并设置ID进入数据库时,解决了问题。
这对我很有用,因为这些查找表,不应该是身份字段,无论如何。
我认为你可能需要退出现有的数据库迁移(即从头开始你的数据库)“Update-Database TargetMigration:0”,然后是“Update-Database”。
实际上,您并没有删除现有的表或值,只是添加/更新这些值。 这需要发生,以获得您想要的结果。
以下是EF迁移的一个很好的参考: http : //elegantcode.com/2012/04/12/entity-framework-migrations-tips/
我使用ID字段作为标识/密钥并添加属性而不是由服务器分配ID。 这解决了我的问题。
public class Hall { [Key] [Required] [DatabaseGenerated(DatabaseGeneratedOption.None)] public int Id {get; set;} public string Name [get; set;} }
就Ciaren的回答来说,在ModelCreating上重置上下文的下面的代码帮助我解决了类似的问题。 确保将“ApplicationContext”更改为您的DbContext名称。
public class ApplicationContext : DbContext, IDbContext { public ApplicationContext() : base("ApplicationContext") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); Database.SetInitializer<ApplicationContext>(null); base.OnModelCreating(modelBuilder); } }