To be blunt, it's wrong from a design perspective to be spinning up DataContext
instances in Add
and Update
methods.
Presumably these methods are in some kind of Repository class - in which case, the repository should be initialized with a pre-existing DataContext
, generally passed in through the constructor.
If you design your repository this way, you don't have to worry about this problem:
public class FooRepository
{
private MyDataContext context;
public FooRepository(MyDataContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void Add(Foo foo)
{
context.FooTable.InsertOnSubmit(foo);
}
public void Update(Foo foo)
{
Foo oldFoo = context.FooTable.Single(f => f.ID == foo.ID);
oldFoo.Bar = foo.Bar;
oldFoo.Baz = foo.Baz;
}
}
Then, from whence you perform your updates:
Foo fooToSave = GetFooFromWherever();
using (MyDataContext context = new MyDataContext(...))
{
FooRepository repository = new FooRepository(context);
repository.Save(fooToSave);
context.SubmitChanges();
} // Done
This pattern can be used and reused, and you can combine multiple repositories into a single "transaction"; you'll never run into any problems with it. This is how the DataContext
, which encapsulates a Unit-of-Work pattern, was actually meant to be used.
Incidentally, when designing a repository, it's common to try to abstract away the cumbersome Insert
/Update
semantics and just expose a Save
method:
public void Save(Foo foo)
{
if (foo.ID == default(int))
{
Insert(foo);
}
else
{
Update(foo);
}
}
That way you're not always having to worry about whether or not you've already inserted your Foo
.
It is possible to coerce Linq to SQL into dealing with detached entities, but good luck getting it to deal with entities that are already attached to a different context. And even in the detached case, it's really quite cumbersome, you need to have timestamp fields on all your tables/entities or start messing with the version check/autosync properties - it's not worth it IMO, just design your repositories to use one context per instance and to share context instances between each other.