Linq to sql使用不同的datacontexts以不同的方法添加/更新

Osk*_*lin 2 c# datacontext linq-to-sql

我需要方法,Add()和Update(),它们都创建一个datacontext并返回创建/更新的对象.

在我的单元测试中,我先调用Add(),做一些东西,然后调用Update().问题是Update()失败并出现异常:

  System.Data.Linq.DuplicateKeyException: Cannot add an entity with a key that is already in use..
Run Code Online (Sandbox Code Playgroud)

我理解这个问题,但想知道该怎么办呢?我已经阅读了一些关于如何处理多个datacontext对象的内容,并且从我听到过这种方式是可以的.

我知道实体仍然附加到Add()中的datacontext但我需要找出如何解决这个问题?

提前致谢

Aar*_*ght 5

坦率地说,从设计的角度来看,在DataContext实例AddUpdate方法中加入实例是错误的.

据推测,这些方法属于某种Repository类 - 在这种情况下,存储库应该使用预先存在的方式初始化DataContext,通常通过构造函数传入.

如果以这种方式设计存储库,则不必担心此问题:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,从那里执行更新:

Foo fooToSave = GetFooFromWherever();
using (MyDataContext context = new MyDataContext(...))
{
    FooRepository repository = new FooRepository(context);
    repository.Save(fooToSave);
    context.SubmitChanges();
} // Done
Run Code Online (Sandbox Code Playgroud)

这种模式可以使用和重用,您可以将多个存储库组合成一个"事务"; 你永远不会遇到任何问题.这就是DataContext封装工作单元模式的实际意图.

顺便提一下,在设计存储库时,通常会尝试抽象出繁琐的Insert/ Update语义并公开一个Save方法:

public void Save(Foo foo)
{
    if (foo.ID == default(int))
    {
        Insert(foo);
    }
    else
    {
        Update(foo);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就不必总是担心你是否已经插入了你的Foo.

可能强迫Linq使用SQL来处理分离的实体,但是很幸运能够让它处理已经附加到不同上下文的实体.即使在分离的情况下,它真的很麻烦,你需要在你的所有表/实体上都有时间戳字段或者开始搞乱版本检查/自动同步属性 - 它不值得IMO,只需设计你的存储库以使用每个上下文实例并在彼此之间共享上下文实例.