C# Entity Framework Code First AddOrUpdate 方法插入重复值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10007351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Entity Framework Code First AddOrUpdate method insert Duplicate values
提问by Y.Yanavichus
I have simple entity:
我有简单的实体:
public class Hall
{
[Key]
public int Id {get; set;}
public string Name [get; set;}
}
Then in the Seedmethod I use AddOrUpdateto populate table:
然后在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
);
Then I run in the Package Management Console:
然后我在包管理控制台中运行:
Add-Migration Current
Update-Database
It's all fine: I have three rows in the table "Hall". But if I run in the Package Management Console Update-Databaseagain I have already five rows:
一切都很好:我在“大厅”表中有三行。但是如果我Update-Database再次在包管理控制台中运行,我已经有五行了:
Id Name
1 French
2 Japaneese
3 German
4 French
5 Japanese
Why? I think it is should be three rows again, not five. I tried to use Idproperty instead of Namebut it does not make the difference.
为什么?我认为应该是三排,而不是五排。我尝试使用Idproperty 而不是Name但它没有区别。
UPDATE:
更新:
This code produces the same result:
此代码产生相同的结果:
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);
Also I have the latest EntityFramework installed via nuget.
我还通过 nuget 安装了最新的 EntityFramework。
采纳答案by Ciaran Bruen
Ok I was banging my face off the keyboard for an hour with this. If your table's Id field is an Identity field then it won't work so use a different one for identifierExpression. I used the Name property and also removed the Id field from the new Hall {...}initializer.
好吧,我用这个把脸从键盘上敲了一个小时。如果您的表的 Id 字段是 Identity 字段,那么它将不起作用,因此对 identifierExpression 使用不同的字段。我使用了 Name 属性并从new Hall {...}初始值设定项中删除了 Id 字段。
This tweak to the OPs code worked for me so I hope it helps someone:
对 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();
}
回答by weeyoung
If object(hall)'s id is 0, it is a insertion. I think you need to double check the id field of your hall objects
如果 object(hall) 的 id 为 0,则为插入。我认为您需要仔细检查大厅对象的 id 字段
回答by Jason
Is your ID field an Identity field? I was running into this same issue. When I removed the Identity status from my ID field and set the IDs going into the database, that resolved the issue.
您的 ID 字段是 Identity 字段吗?我遇到了同样的问题。当我从我的 ID 字段中删除身份状态并将 ID 设置到数据库中时,问题解决了。
That worked for me, since these were look-up tables and shouldn't have been identity fields, anyway.
这对我有用,因为这些是查找表,无论如何都不应该是身份字段。
回答by Daryn
I have found that AddOrUpdateworks fine with fields that are not ID's. If this works for you: context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)
我发现它AddOrUpdate适用于非 ID 的字段。如果这对你有用:context.Halls.AddOrUpdate(h => h.Name, hall1, hall2, hall3)
You may want to use Hall names like 'French_test_abc_100', 'German_test_abc_100' etc.
您可能想使用大厅名称,如“French_test_abc_100”、“German_test_abc_100”等。
That stops hard coded test data messing things up when you are testing your app.
当你测试你的应用程序时,这会阻止硬编码的测试数据把事情搞砸。
回答by Y.Yanavichus
This code works:
此代码有效:
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();
}
回答by firecape
This can also be caused if you're setting the Entity State incorrectly. I kept getting the following error when I'd run update-database..."Sequence contains more than one matching element."
如果您不正确地设置实体状态,也可能导致这种情况。当我运行 update-database 时,我不断收到以下错误......“序列包含多个匹配元素。”
For example, I had duplicate rows being created on each update-database command (which of course is not supposed to happen when seeding data), and then the next update-database command wouldn't work at all since it found more than one match (hence the sequence error saying I have more than one matching row). That's because I had overridden SaveChanges in my context file with a method call to ApplyStateChanges...
例如,我在每个 update-database 命令上创建了重复的行(这当然在播种数据时不应该发生),然后下一个 update-database 命令根本不起作用,因为它找到了多个匹配项(因此序列错误说我有多个匹配行)。那是因为我使用对 ApplyStateChanges 的方法调用覆盖了上下文文件中的 SaveChanges...
public override int SaveChanges()
{
this.ApplyStateChanges();
return base.SaveChanges();
}
I was using ApplyStateChanges to ensure that when adding object graphs, Entity Framework knows explicitly whether the object is in an added or modified state. The entire explanation on how I'm using ApplyStateChanges can be found here.
我使用 ApplyStateChanges 来确保在添加对象图时,实体框架明确知道对象是处于添加状态还是修改状态。可以在此处找到有关我如何使用 ApplyStateChanges 的完整说明。
And this works great (but the caveat!!)...if you're also seeding the database using CodeFirst migrations, then the above method will cause havoc for the AddOrUpdate() call within the Seed Method. So before anything else, just check your DBContext file and ensure you're not overriding SaveChanges in the way above, or you will end up getting duplicate data running the update-database command a second time, and then won't work at all the third time since there's more than one row for each matching item.
这很有效(但要注意!!)...如果您还使用 CodeFirst 迁移为数据库做种,那么上述方法将对 Seed 方法中的 AddOrUpdate() 调用造成严重破坏。因此,在做任何其他事情之前,只需检查您的 DBContext 文件并确保您没有以上述方式覆盖 SaveChanges,否则您将最终获得第二次运行 update-database 命令的重复数据,然后根本无法工作第三次,因为每个匹配项都有不止一行。
When it comes down to it, you don't need to configure the Id in AddOrUpdate()...that defeats the whole purpose of easy and initial database seeding. It works fine by something like:
归根结底,您不需要在 AddOrUpdate() 中配置 Id ……这违背了简单和初始数据库播种的全部目的。它可以通过以下方式正常工作:
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" },
just AS LONG as I'm not overriding the SaveChanges method in my context file with a call to ApplyStateChanges. Hope this helps.
只要我没有通过调用 ApplyStateChanges 覆盖我的上下文文件中的 SaveChanges 方法。希望这可以帮助。
回答by Harvey Powers
I think it's likely that you need to back out existing database migrations (i.e. start your database from scratch) with something like Update-Database TargetMigration:0followed by Update-Database.
我认为您可能需要使用Update-Database TargetMigration:0后跟Update-Database.
As it is, you're not dropping the existing table or values, you're just add/updating those values. That needs to happen in order to get your desired result.
事实上,您不会删除现有的表或值,您只是添加/更新这些值。这需要发生才能获得您想要的结果。
回答by Anthony Nichols
I know this is an old question, but the right answer is that if you are setting the id # yourself and you want to use AddOrUpdate then you need to tell EF/SQL that you don't want it to generate the ID #.
我知道这是一个老问题,但正确的答案是,如果您自己设置 id # 并且想要使用 AddOrUpdate,那么您需要告诉 EF/SQL 您不希望它生成 ID #。
modelBuilder.Entity<MyClass>().Property(p => p.Id)
.HasDatabaseGeneratedOption(System.ComponentModel
.DataAnnotations.Schema.DatabaseGeneratedOption.None);
The down side to this is that when you insert a new item you need to set it's Id, so if this is done dynamically at runtime (instead of from seed data) then you will need to calculate out the next Id. Context.MyClasses.Max(c=>c.Id) + 1works well.
不利的一面是,当您插入一个新项目时,您需要设置它的 Id,因此如果这是在运行时动态完成的(而不是从种子数据),那么您将需要计算出下一个 Id。 Context.MyClasses.Max(c=>c.Id) + 1效果很好。
回答by Guntars
I used the ID field as Identity/Key and add attributes not to assign Ids by the server. This solved the problem for me.
我使用 ID 字段作为身份/密钥,并添加了不由服务器分配 ID 的属性。这为我解决了这个问题。
public class Hall
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id {get; set;}
public string Name [get; set;}
}
回答by Riyaz Hameed
Just to Ciaren's answer, the below code of resetting the context on ModelCreating, helped me resolve similar issues. Make sure change "ApplicationContext" to your DbContext name.
对于 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);
}
}

