LINQ to SQL:附加或不附加

Bra*_*ler 9 c# linq-to-sql

所以我有一个真的很难搞清楚的时候我应该连接到一个对象,我不应该附加到的对象.首先,这是我(非常简化)对象模型的一个小图.

架构

在我的DAL中,每次进行数据相关操作时都会创建一个新的DataContext.比如说,我想保存一个新用户.在我的业务层中,我创建了一个新用户.

var user = new User();
user.FirstName = "Bob";
user.LastName = "Smith";
user.Username = "bob.smith";
user.Password = StringUtilities.EncodePassword("MyPassword123");
user.Organization = someOrganization; // Assume that someOrganization was loaded and it's data context has been garbage collected.
Run Code Online (Sandbox Code Playgroud)

现在我想去保存这个用户.

var userRepository = new RepositoryFactory.GetRepository<UserRepository>();
userRepository.Save(user);
Run Code Online (Sandbox Code Playgroud)

NEATO!这是我的保存逻辑:

public void Save(User user)
{
 if (!DataContext.Users.Contains(user))
 {
  user.Id = Guid.NewGuid();
  user.CreatedDate = DateTime.Now;
  user.Disabled = false;

  //DataContext.Organizations.Attach(user.Organization);
  DataContext.Users.InsertOnSubmit(user);
 }
 else 
 {
  DataContext.Users.Attach(user);
 }

 DataContext.SubmitChanges();

 // Finished here as well.
 user.Detach();
}
Run Code Online (Sandbox Code Playgroud)

所以,我们来了.您会注意到我将DataContext附加到组织的位置注释掉.如果我附加到组织,我会收到以下异常:

NotSupportedException: 尝试附加或添加非新的实体,可能是从另一个DataContext加载的实体.这不受支持.

嗯,这不起作用.让我试试它而不附加(即注释掉关于附加到组织的那一行).

DuplicateKeyException: 无法添加具有已在使用的密钥的实体.

WHAAAAT?我只能假设这是试图插入一个显然是假的新组织.

那么,这些交易是什么人?我该怎么办?什么是正确的方法?似乎L2S让它变得比它应该更难......

编辑:我刚刚注意到,如果我尝试查看挂起的更改集(dataContext.GetChangeSet()),我得到了我之前描述的相同的NotSupportedException !! 怎么了,L2S?!

小智 7

它可能无法完全像这样工作,但这是我概念化它的方式:当你从DataContext召唤一个对象时,Linq所做的事情之一是跟踪这个对象随时间的变化,所以它知道要保存什么如果你提交更改.如果丢失了这个原始数据上下文,从它召唤的Linq对象没有从它从数据库中召唤的时间内发生的变化的历史记录.

例如:

DbDataContext db = new DbDataContext();
User u = db.Users.Single( u => u.Id == HARD_CODED_GUID );
u.FirstName = "Foo";
db.SubmitChanges();
Run Code Online (Sandbox Code Playgroud)

在这种情况下,由于User对象是从数据上下文中召唤出来的,因此它跟踪了对"u"的所有更改,并知道如何将这些更改提交给数据库.

在您的示例中,您有一个User对象,该对象已在某个地方持久化(或从其他地方传递,并且没有它被传唤的原始DataContext).在这种情况下,您必须将其附加到新数据上下文.

User u; // User object passed in from somewhere else
DbDataContext db = new DbDataContext();
u.FirstName = "Foo";
DbDataContext.Users.Attach( u );
db.SubmitChanges();
Run Code Online (Sandbox Code Playgroud)

由于用户和组织之间的关系只是数据模型中的GUID(OrganizationId),因此您只需附加用户对象.

我不确定你的脚手架代码,但也许是这样的:

    private const Guid DEFAULT_ORG = new Guid("3cbb9255-1083-4fc4-8449-27975cb478a5");
    public void Save(User user)
    {
        if (!DataContext.Users.Contains(user))
        {
            user.Id = Guid.NewGuid();
            user.CreatedDate = DateTime.Now;
            user.Disabled = false;
            user.OrganizationId = DEFAULT_ORG; // make the foreign key connection just
                                               // via a GUID, not by assigning an
                                               // Organization object

            DataContext.Users.InsertOnSubmit(user);
        }
        else
        {
            DataContext.Users.Attach(user);
        }

        DataContext.SubmitChanges();

    }
Run Code Online (Sandbox Code Playgroud)


Dav*_*kle 1

因此,当您获取数据库中存在的对象、将其分离(例如通过其他地方的 Web 服务将其编组)并希望将其放回数据库时,将使用“附加”。不要调用 .Attach(),而是调用 .InsertOnSubmit()。从概念上讲你已经差不多了,你只是使用了错误的方法来做你想做的事。