«Присоединить или добавить объект, который не является новым ... загружен из другого DataContext. Это не поддерживается.» Проблема при вставке объекта компоновщика - PullRequest
1 голос
/ 27 апреля 2010

Подобная ошибка, как и другие вопросы, но не совсем то же самое, я не пытаюсь ничего прикрепить.

То, что я пытаюсь сделать, это вставить новую строку в таблицу ссылок, в частности 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 два соответствующих объекта, это, естественно, сработает, если пользователь или Accomplishment уже существуют. Это работает только тогда, когда пользователь и достижение не существуют. Я ожидал такого поведения. То, что работает, - это просто предоставление объекту userAccomplishment user.id и assignment.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."

Я отлаживал это несколько раз сейчас и не уверен, почему это происходит, если существует Пользователь или Выполнение, я не включаю его в конечный объект, чтобы попытаться вставить. Так что, похоже, ничего не пытались добавить. Даже при отладке после вставки объект был пустым. Итак, достижение новое, а пользователь пуст.

1) Почему это все еще говорит, и как я могу это исправить .. используя мою текущую структуру

2) Упреждающее «использовать ответы из шаблона репозитория» - я знаю, что этот способ вообще отстой, и мне следует использовать шаблон репозитория. Тем не менее, я не могу использовать это в текущем проекте, потому что у меня нет времени на рефакторинг, потому что я не знаю об этом и ограничен во времени. Использование приложения будет настолько малым, что неэффективное использование datacontext и того, что у вас есть, не будет иметь большого значения. Я могу реорганизовать его, как только он будет запущен и запущен, но сейчас мне просто нужно «протолкнуть» мою текущую структуру.

Редактировать: Я также только что проверил это, когда оба они уже существуют, и вставляю только идентификаторы каждого объекта в таблицу, которая работает. Так что, я думаю, я мог бы вручную вставить любой объект, который не существует, как одну вставку, а затем поместить идентификаторы только в таблицу ссылок, но я до сих пор не знаю, почему, когда существует один объект, и я делаю его пустым, он становится " т работа.

1 Ответ

2 голосов
/ 28 апреля 2010

Прежде всего, я думаю, что вы слишком усердно работаете, но это понятно.

Дайте мне посмотреть, если вы понимаете, что вы пытаетесь сделать: вы хотите обновить таблицу ассоциаций, которая отслеживает пользователей и достижения. Независимо от того, что существует заранее, к тому времени, когда вы закончите, вам понадобится действительная запись 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();       
    }
}

Дайте мне знать, если это поможет ...

...