【问题标题】:"Attach or Add an entity that is not new...loaded from another DataContext. This is not supported." Problem on insert of linker object“附加或添加一个不是新的实体......从另一个 DataContext 加载。不支持。”链接器对象插入问题
【发布时间】:2010-04-27 18:49:38
【问题描述】:

与其他问题类似的错误,但不完全相同,我没有尝试附加任何内容。

我要做的是在链接表中插入一个新行,特别是 UserAccomplishment。关系在 LINQ 中设置为用户和成就表。

我有一个通用的插入函数:

Public Function insertRow(ByVal entity As ImplementationType) As Boolean
        If entity IsNot Nothing Then

            Dim lcfdatacontext As New LCFDataContext()
            Try
                lcfdatacontext.GetTable(Of ImplementationType)().InsertOnSubmit(entity)

                lcfdatacontext.SubmitChanges()
                lcfdatacontext.Dispose()
                Return True
            Catch ex As Exception
                Return False
            End Try
        Else
            Return False
        End If
End Function

如果您尝试为 UserAccomplishment 提供两个适当的对象,如果 User 或 Accomplishment 已经存在,这自然会出错。它仅在用户和成就都不存在时才有效。我预料到了这种行为。起作用的只是简单地给 userAccomplishment 对象一个 user.id 和 completion.id 并填充其余字段。这可行,但在我的应用程序中使用有点尴尬,简单地传入两个对象并让它计算出已经存在的内容和不存在的内容会容易得多。好的,所以我做了以下事情(请忽略这样一个事实,因为我知道这是非常低效的):

Public Class UserAccomplishmentDao
    Inherits EntityDao(Of UserAccomplishment)

    Public Function insertLinkerObjectRow(ByVal userAccomplishment As UserAccomplishment)

        Dim insertSuccess As Boolean = False

        If Not userAccomplishment Is Nothing Then

            Dim userDao As New UserDao()
            Dim accomplishmentDao As New AccomplishmentDao()
            Dim user As New User()
            Dim accomplishment As New Accomplishment()


            'see if either object already exists in db'
            user = userDao.getOneByValueOfProperty("Id", userAccomplishment.User.Id)
            accomplishment = accomplishmentDao.getOneByValueOfProperty("Id", userAccomplishment.Accomplishment.Id)


            If user Is Nothing And accomplishment Is Nothing Then
                'neither the user or the accomplishment exist, both are new so insert them both, typical insert'
                insertSuccess = Me.insertRow(userAccomplishment)

            ElseIf user Is Nothing And Not accomplishment Is Nothing Then
                'user is new, accomplishment is not new, so just insert the user, and the relation in userAccomplishment'
                Dim userWithExistingAccomplishment As New UserAccomplishment(userAccomplishment.User, userAccomplishment.Accomplishment.Id, userAccomplishment.LastUpdatedBy)
                insertSuccess = Me.insertRow(userWithExistingAccomplishment)
            ElseIf Not user Is Nothing And accomplishment Is Nothing Then
                'user is not new, accomplishment is new, so just insert the accomplishment, and the relation in userAccomplishment'
                Dim existingUserWithAccomplishment As New UserAccomplishment(userAccomplishment.UserId, userAccomplishment.Accomplishment, userAccomplishment.LastUpdatedBy)
                insertSuccess = Me.insertRow(existingUserWithAccomplishment)
            Else
                'both are not new, just add the relation'
                Dim userAccomplishmentBothExist As New UserAccomplishment(userAccomplishment.User.Id, userAccomplishment.Accomplishment.Id, userAccomplishment.LastUpdatedBy)
                insertSuccess = Me.insertRow(userAccomplishmentBothExist)
            End If

        End If

        Return insertSuccess

    End Function

End Class

好的,这里我主要检查提供的用户和成就是否已经存在于数据库中,如果存在,则调用适当的构造函数,将已经存在的任何内容留空,但提供其余信息以便插入成功。

但是,在尝试插入时:

Dim result As Boolean = Me.userAccomplishmentDao.insertLinkerObjectRow(userAccomplishment)

用户已经存在,但成就不存在(99% 的典型场景)我得到错误:

"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."

我现在已经调试了很多次,但不确定为什么会发生这种情况,如果 User 或 Accomplishment 存在,我不会将它包含在尝试插入的最终对象中。因此,似乎没有尝试添加任何内容。即使在调试中,插入时,对象也被设置为空。所以成就是新的,用户是空的。

1) 为什么它仍然这么说,我该如何修复它..使用我当前的结构

2) 先发制人的“使用存储库模式答案” - 我知道这种方式通常很糟糕,我应该使用存储库模式。但是,我不能在当前项目中使用它,因为由于我不知道它和时间限制,我没有时间重构它。该应用程序的使用量将变得如此之小,以至于数据上下文的低效使用以及您拥有的东西都不会那么重要。一旦它启动并运行,我就可以重构它,但现在我只需要用我当前的结构“推进”。

编辑:我也只是在两者都已经存在时对此进行了测试,并且只将每个对象的 ID 插入到表中,这是可行的。所以我想我可以手动插入任何不存在的对象作为单个插入,然后只将 id 放入链接表中,但我仍然不知道为什么当一个对象存在时,我将其设为空,它确实如此'没用。

【问题讨论】:

    标签: .net linq linq-to-sql insert datacontext


    【解决方案1】:

    首先,我认为你工作太努力了,但这是可以理解的。

    让我看看你是否理解你想要做什么:你想更新一个跟踪用户和成就的关联表。无论事先存在什么,当您完成时,您都需要一个有效的 UserAccomplishment 记录,其中包含已完成且有效的关系。让我们开始吧:

    public void AddUserAccomplishment(user User, accomplishment Accomplishment)
    {
        using (LCFDataContext dc = new LCFDataContext())
        {
            // Substitute <UserName> for any other unique field in the record.
            var tempUser = dc.Users
                .Where(a => a.UserName.ToLower() == user.UserName.ToLower())
                .SingleOrDefault();
    
            // Using SingleOrDefault() creates an empty User entity object if 
            // a matching record can't be found, which means the Id field will
            // be equal to zero.
            if (tempUser.Id == 0)
            {
                // Populate the empty tempUser entity object
                tempUser.UserName = user.UserName;
                   .
                   .
                   .
                dc.Users.InsertOnSubmit(tempUser);
            }
    
            // Do the same thing for the Accomplishment.
            var tempAccomplishment = dc.Accomplishments
                .Where(a => a.Title.ToLower() == accomplishment.Title.ToLower())
                .SingleOrDefault();
    
            if (tempAccomplishment.Id == 0)
            {
                // Populate the empty tempAccomplishment entity object
                tempAccomplishment.Title = accomplishment.Title;
                   .
                   .
                   .
                dc.Accomplishments.InsertOnSubmit(tempAccomplishment);
            }
    
            // Now, you need to make sure that the UserAccomplishment entity object
            // doesn't already exist.
            if (dc.UserAccomplishments
                .Where(a => a.User.Id == tempUser.Id
                    && a.Accomplishment.Id == tempAccomplishment.Id)
                .Count == 0)
            {
                UserAccomplishment userAccomplishment = new UserAccomplishment();
    
                userAccomplishment.User = tempUser;
                userAccomplishment.Accomplishment = tempAccomplishment;
                dc.UserAccomplishments.InsertOnSubmit(userAccomplishment);
            }
            else
            {
                // The UserAccomplishment record already exists, so throw an
                // exception or display an error message.
            }
    
            dc.SubmitChanges();       
        }
    }
    

    如果这有帮助,请告诉我...

    【讨论】:

    • 感谢 Neil T. 的工作就像一个魅力,是的,你的工作更容易一些。我想我只是太努力地使用我的通用函数,但是随着它们获得不同的数据上下文,它会导致问题。对我来说,处理 dataContexts 仍然很困难。
    • 就个人而言,我更喜欢使用单个 DataContext。我当前的 Web 项目有大约 60-70 个表,其中包含多个 M-M 关系。尝试协调多个 DataContexts 之间的活动不会很有趣......为了获得我不断听到(但从未目睹)拥有多个 DC 的好处,我必须将我当前的 DC 分解为至少 8-10较小的 DC。我什至不想尝试管理这种粒度级别。
    • 那么你所有的函数都写在了 DAL 层中,并使用了像上面这样的用法?还是使用存储库模式?我在存储库模式中看到的一个问题(我认为)是使用它的类必须作为 using 语句调用,但是它是如何工作的,然后你想在 page_load 上调出一些对象,然后将它们保存在单击按钮?另外我可能不清楚,但在我原来的评论中,我的意思是不同的 dataContext 实例,听起来你正在讨论不同的 dataConext 类。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    相关资源
    最近更新 更多