Assuming the model be like:
class Foo {
virtual Bar Bar {get; set ;}
}
class Bar {
int Id { get; set; }
string Property {get; set;}
}
class MyContext {
virtual DbSet<Foo> Foos {get; set;}
void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Bar>()
.HasKey(c => c.Property);
}
}
And some code like:
void DoStuff() {
var foos = GetFoosFromExternalSource();
using(var ctx = new MyContext() {
foreach(var foo in foos) {
ctx.Foos.Add(foo);
}
ctx.SaveChanges();
}
}
IEnumerable<Foo> GetFoosFromExternalSource() {
yield return new Foo {
Bar = new Bar { Id = 1, Property = "Hello" }
};
yield return new Foo {
Bar = new Bar { Id = 2, Property = "World" }
};
yield return new Foo {
Bar = new Bar { Id = 1, Property = "Hello" }
}
}
This throws an exception:
Violation of PRIMARY KEY constraint 'PK_dbo.Bar'. Cannot insert duplicate key in object 'dbo.Bar'. The duplicate key value is (Hello).
How can I make it clear to EF that if a Bar object has the same Key (or Id, or Both) that it is considered the same instance?
I know that if I could do something like
IEnumerable<Foo> GetFoosFromExternalSource() {
var bar1 = new Bar { Id = 1, Property = "Hello" };
var bar2 = new Bar { Id = 2, Property = "World" };
yield return new Foo {
Bar = bar1
};
yield return new Foo {
Bar = bar2
};
yield return new Foo {
Bar = bar1
}
}
It would work fine. However, since this is data coming from an external source this is not directly possible. My real scenario has multiple levels and a lot of properties. So I would like to solve this in the model.
Instead of adding the entities, you should use an "upsert" library (or create your own). For example FlexLabs.Upsert is such a library for Entity Framework Core.
In your case the code would then look like the following (based on docu):
async Task DoStuff()
{
var foos = GetFoosFromExternalSource();
using(var ctx = new MyContext()
{
await ctx.Foos
.UpsertRange(foos)
.On(f => f.Property)
.RunAsync();
ctx.SaveChanges(); // not sure if savechanges call is necessary based on docu...
}
}
Notes: I have not used FlexLabs.Upsert before, a friend recommend it to me some time ago, have not yet had the time to experiment further with it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.