c# - LINQ 到 SQL : To Attach or Not To Attach

标签 c# linq-to-sql

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

Schema

在我的 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.

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

var userRepository = new RepositoryFactory.GetRepository<UserRepository>();
userRepository.Save(user);

内托!这是我的保存逻辑:

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();
}

所以,我们到了。您会注意到我注释掉了 DataContext 附加到组织的位。如果我加入组织,我会得到以下异常:

NotSupportedException: An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.

嗯,那行不通。让我尝试附加(即注释掉关于附加到组织的那一行)。

DuplicateKeyException: Cannot add an entity with a key that is already in use.

什么?我只能假设这是在尝试插入一个显然是错误的新组织。

那么,伙计们,这是怎么回事?我应该怎么办?什么是正确的方法?看起来 L2S 使这比它应该做的要难得多......

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

最佳答案

它在幕后可能并不完全像这样工作,但这是我对其进行概念化的方式:当您从 DataContext 中调用一个对象时,Linq 所做的其中一件事就是跟踪该对象随时间的变化,以便它知道什么如果您提交更改,则保存回来。如果您丢失了这个原始数据上下文,从中调用的 Linq 对象就没有自从从数据库中调用以来发生的更改的历史记录。

例如:

DbDataContext db = new DbDataContext();
User u = db.Users.Single( u => u.Id == HARD_CODED_GUID );
u.FirstName = "Foo";
db.SubmitChanges();

在这种情况下,由于 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();

由于用户和组织之间的关系在您的数据模型中只是一个 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();

    }

关于c# - LINQ 到 SQL : To Attach or Not To Attach,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2679698/

相关文章:

linq-to-sql - 如何在 LINQ-To-SQL (IDENTITY INSERT) 中手动设置标识字段

c# - .Select 不更新 View 模型对象的 ObservableCollection

c# - 为什么 MediaElement 不播放 MediaStreamSource(在 SilverLight 中)?

c# - 服务器和客户端之间实现心跳的模式

c# - 使用 Linq to SQL 存储库的可能性能注意事项

c# - 为什么 Entity Framework 不能在 LINQ 语句中使用 ToString()?

c# - 错误: A query body must end with a select clause or a group clause

c# - 多列的 LINQ GroupBy

sql - 使用 SQL Server Express 进行 SQL Server Standard 开发?

linq-to-sql - 如何仅使用主键删除?