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

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