Reputation: 21709
I have a POCO A
entity referencing a B
entity, let's say b
. I want A
to reference a different exising B
entity, let's say bb
.
These steps:
var b = // get existing b from somewhere out-of-context
var a = new A { B = b }
dbcontext.Set<B>.Attach(a.B);
dbcontext.Set<A>.Add(a);
context.SaveChanges();
generate an insert statement for a
as expected with the B_ID
foreign key properly set to the primary key ID of b
. These subsequent steps:
var bb = // get existing bb from somewhere out-of-context
a.B = bb;
differentdbcontext.Set<B>.Attach(a.B);
differentdbcontext.Set<A>.Attach(a);
differentdbcontext.Entry(a).State = EntityState.Modified;
differentdbcontext.SaveChanges();
result in no change to the persisted data. The update statement does not include the set B_ID = ...
as expected.
I'm doing something simple wrong as I've had other scenarios like this working before.
Upvotes: 1
Views: 212
Reputation: 177133
Setting the state to Modified
only has an effect on scalar properties but not on your navigation properties. I assume that B_ID
is not a property in your model but only the foreign key column in the database not being exposed to your model.
In this case you can update the relationship only by leveraging the automatic change detection of Entity Framework. One approach - and I would call this the standard approach - is to load the original A
including the original B
from the database, set a.B
to your new bb
and then save the changes:
var bb = // get existing bb from somewhere out-of-context
differentdbcontext.Set<B>().Attach(bb);
differentdbcontext.Set<A>().Include(x => x.B).Single(x => x.Id == a.Id);
a.B = bb;
differentdbcontext.SaveChanges();
If you don't want to load the original from the DB some trick programming is required:
var bb = // get existing bb from somewhere out-of-context
if ( (a.B == null && bb != null)
|| (a.B != null && bb == null)
|| (a.B != null && bb != null && a.B.Id != bb.Id)) //take care not to attach
//two objects with same key
{
if (bb != null)
differentdbcontext.Set<B>().Attach(bb);
differentdbcontext.Set<A>().Attach(a);
a.B = bb; // EF will detect this change
}
else if (a.B == null && bb == null)
{
// create a dummy a.B
a.B = new B(); // it doesn't matter which Id
differentdbcontext.Set<A>().Attach(a);
a.B = bb; // = null -> EF will detect a change
}
differentdbcontext.SaveChanges();
Or similar. The idea is to change the reference after attaching the objects so that change detection will send an update of the FK column to the database.
Exposing foreign keys as properties into your model will make this situation much easier. Setting the state to Modified
would work then because FK properties are scalar.
Upvotes: 1