Linq to sql add/update in different methods with different datacontexts

后端 未结 4 1559

I have to methods, Add() and Update() which both create a datacontext and returns the object created/updated.

In my unit test I call first Add(), do some stuff and

4条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-07 07:46

    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.

提交回复
热议问题