Knowning Foo.Id
and Bar.Id
how can I create their relation without loading the entities from the DB.
class Foo {
public in
If I'm understanding correctly, you wanted to add Bar object to an existing Foo entity without making a lookup for Foo entity.
Let say, you have Foo (id = 1) already exists. Wanted to add new Bar (id = 100) entity to it.
using (var context = new Context())
{
var bar = new Bar() { Id = 100 };
var foo = new Foo() { Id = 1 }; // Only ID is required
context.Foos.Attach(foo);
bar.Foos.Add(foo);
context.Bars.Add(bar);
context.SaveChanges();
}
Ok, have found the solution and here is the helper method:
static void ChangeRelationship<T1, T2>(
IObjectContextAdapter ctx,
T1 a,
T2 b,
Expression<Func<T1, object>> getNavigationProperty,
EntityState state) where T1: class
{
ctx
.ObjectContext
.ObjectStateManager
.ChangeRelationshipState(
a,
b,
getNavigationProperty,
state
);
}
And using it in my example from the question:
using (var ctx = new DbCtx())
{
ctx.Configuration.LazyLoadingEnabled = false;
ctx.Configuration.ProxyCreationEnabled = false;
ctx.Configuration.AutoDetectChangesEnabled = false;
ctx.Database.Log += Console.WriteLine;
var foo = new Foo {Id = 1, Bars = new List<Bar>()};
var bar = new Bar { Id = 3, Foos = new List<Foo>() };
ctx.Entry(foo).State = EntityState.Unchanged;
ctx.Entry(bar).State = EntityState.Unchanged;
// create
ChangeRelationship(ctx, foo, bar, x => x.Bars, EntityState.Added);
ctx.SaveChanges();
// remove
ChangeRelationship(ctx, foo, bar, x => x.Bars, EntityState.Deleted);
ctx.SaveChanges();
}
What you are asking is possible. Here are the steps:
(1) Start by creating two entity instances with just PK specified and attach one of them (for instance foo
) to the context:
var foo = new Foo { Id = fooId };
var bar = new Bar { Id = barId };
ctx.Foos.Attach(foo);
(2) Set the second entity collection to a new list containing the first entity (i.e. "create" the relation):
bar.Foos = new List<Foo> { foo };
(3) Mark the second entity as follows:
(A) To add relation:
ctx.Entry(bar).State = EntityState.Added;
(B) To remove relation:
ctx.Entry(bar).State = EntityState.Deleted;
(4) Mark the second entity as unchanged:
ctx.Entry(bar).State = EntityState.Unchanged;
And that's it!
Once you call ctx.SaveChanges();
, the relation will be added or removed from the junction table.
Update: While the above works (actually my original solution of attaching the second entity with the "original" collection and then simulating modification also works if we call at the end DbContext.ChangeTracker.DetectChanges()
explicitly), I should admit that the ObjectContext
solution you found looks much more natural (it's strange that such functionality has not been exposed via DbContext
), so my personal vote goes there.