"Attach or Add an entity that is not new...loaded from another DataContext. This is not supported."

Posted by sah302 on Stack Overflow See other posts from Stack Overflow or by sah302
Published on 2010-04-27T18:49:38Z Indexed on 2010/04/27 18:53 UTC
Read the original article Hit count: 291

Filed under:
|
|
|

Similar error as other questions, but not quite the same, I am not trying to attach anything.

What I am trying to do is insert a new row into a linking table, specifically UserAccomplishment. Relations are set in LINQ to User and Accomplishment Tables.

I have a generic insert function:

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

If you try and give UserAccomplishment the two appropriate objects this will naturally crap out if either the User or Accomplishment already exist. It only works when both user and accomplishment don't exist. I expected this behavior. What does work is simply giving the userAccomplishment object a user.id and accomplishment.id and populating the rest of the fields. This works but is kind of awkward to use in my app, it would be much easier to simply pass in both objects and have it work out what already exists and what doesn't. Okay so I made the following (please ignore the fact that this is horribly inefficient because I know it is):

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

Alright, here I basically check if the supplied user and accomplishment already exists in the db, and if so call an appropriate constructor that will leave whatever already exists empty, but supply the rest of the information so the insert can succeed.

However, upon trying an insert:

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

In which the user already exists, but the accomplishment does not (the 99% typical scenario) I get the error:

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

I have debugged this multiple times now and am not sure why this is occuring, if either User or Accomplishment exist, I am not including it in the final object to try to insert. So nothing appears to be attempted to be added. Even in debug, upon insert, the object was set to empty. So the accomplishment is new and the user is empty.

1) Why is it still saying that and how can I fix it ..using my current structure

2) Pre-emptive 'use repository pattern answers' - I know this way kind of sucks in general and I should be using the repository pattern. However, I can't use that in the current project because I don't have time to refactor that due to my non existence knowledge of it and time constraints. The usage of the app is going to so small that the inefficient use of datacontext's and what have you won't matter so much. I can refactor it once it's up and running, but for now I just need to 'push through' with my current structure.

Edit: I also just tested this when having both already exists, and only insert each object's IDs into the table, that works. So I guess I could manually insert whichever object doesn't exist as a single insert, then put the ids only into the linking table, but I still don't know why when one object exists, and I make it empty, it doens't work.

© Stack Overflow or respective owner

Related posts about LINQ

Related posts about linq-to-sql