When I am creating a new A
record, I know that A
and B
will be new entries. C
will always be an existing entity so I must make sure not to create a new C
object or my database will have duplicates and my logic will fail.
Here is a representation of my model:
public class A
{
public int ID { get; set; }
public string Value { get; set; }
public virtual ICollection<B> Bs { get; set; }
}
public class B
{
public int ID { get; set; }
public string Value { get; set; }
public virtual A A { get; set; }
public virtual ICollection<C> Cs { get; set; }
}
public class C
{
public int ID { get; set; }
public string Value { get; set; }
public virtual ICollection<B> Bs { get; set; }
}
And my seed method:
protected override void Seed(IdentifyingBug.MyDbContext context)
{
context.Cs.AddOrUpdate(
c => c.ID,
new C() { ID = 101, Value = "An existing C value" },
new C() { ID = 202, Value = "Another existing C value" },
new C() { ID = 303, Value = "Again, another existing C value" }
);
}
Due to how my actual application is structured I cannot use the same context and I must add a dettached entity and manually modify the state myself.
The below code represents the general structure of my code and the exact error I am getting:
public Dictionary<string, A> Received = new Dictionary<string, A>();
public void CreateObject(string token)
{
var a = new A() { Value = "New value for A" };
List<B> bList = new List<B>();
bList.Add( new B() { Value = "New value for B1" });
bList.Add( new B() { Value = "New value for B2" });
foreach (var b in bList)
{
List<C> cList = new List<C>();
using (var db = new MyDbContext())
{
foreach (var c in db.Cs)
{
cList.Add(c);
}
}
b.Cs = cList;
}
a.Bs = bList;
Received.Add(token, a);
}
public async Task<A> GetObject(string token)
{
A a;
while (!Received.TryGetValue(token, out a))
{
await Task.Delay(100);
}
return a;
}
public async void button1_Click(object sender, EventArgs e)
{
string token = "qwerty";
CreateObject(token);
A a = await GetObject(token);
using (var db = new MyDbContext())
{
db.As.Add(a);
// attempt to set all C entities to unchanged but fails because of duplicate primary key
foreach (var b in a.Bs)
{
foreach (var c in b.Cs)
{
db.Entry<C>(c).State = EntityState.Unchanged;
}
}
db.SaveChanges();
}
}
This code results in the exception:
Saving or accepting changes failed because more than one entity of type 'Project.C' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.
Multiple Bs inside A can have the same C. How do I tell entity framework that the Cs with the same primary ID are to be treated as the same entity and not throw an error?
(Again to be clear, I must save the dettached object, I am unable to share the context)