Подтвердить что ты не робот

Linq2sql: невозможно добавить объект с уже существующим ключом

У меня есть установка linq2sql, где объекты отправляются с клиентской стороны (flex через flourinefx) и присоединяют их к новому datacontext, показанному ниже:

У меня также есть "глобальный" datacontext, который используется на протяжении всего сеанса.

    public static void Update(Enquiry enquiry)
    {
        OffertaDataContext db = new OffertaDataContext();


        db.Enquiries.Attach(enquiry);
        db.Refresh(RefreshMode.KeepCurrentValues, enquiry);

        db.SubmitChanges();
    }

Этот подход обычно работает нормально, но через некоторое время я получаю сообщение об ошибке "Невозможно добавить объект с ключом, который уже используется".

4b9b3361

Ответ 1

Я думаю, что эта ошибка возникает, если вы Attach сущность к DataContext, которая уже была загружена.

Код, вызывающий ошибку, точно так же, как вы здесь показываете? После создания нового OffertaDataContext вы запрашиваете что-либо перед Attach?

Ответ 2

Я получал эту ошибку, и это произошло потому, что я забыл установить в поле "Основной ключ" базу данных "Спецификация идентификатора" (автоинкремент). Когда я изменил это, я был хорош. Doh!

Ответ 3

Возможно, это не ваша проблема (я не могу сказать), но она была моей, и, как люди google, это могло помочь кому-то другому. Если вы не используете встроенный конструктор Linq-to-SQL или материал SQLMetal для генерации ваших классов Linq-to-SQL, или если вы забыли сделать свой столбец ID IDENTITY, вы можете потерять свойство в своей колонке атрибут "IsDbGenerated". Убедитесь, что атрибут столбца выглядит примерно так:

<Column(Name:="ID", DbType:="Int NOT NULL IDENTITY", CanBeNull:=False, IsPrimaryKey:=True, IsDbGenerated:=True)>

Ответ 4

Вы пытаетесь добавить несколько новых объектов в один хит, где LinqEntities создаются с помощью клавиши 0?

У меня была эта проблема в прошлом, когда я пытался добавить элементы в таблицу на моей странице, а затем, когда я попытался удалить или обновить эти элементы, у кратных будет ключ 0. Так что очевидно, что он не знал, что делать с моими запросами...

Ответ 5

Если вы вставляете сразу несколько объектов, возможно, вы просто пытаетесь вставить дублирующийся объект в текущий datacontext. Я знаю, что это слишком просто, но это случилось с самим собой.

Ответ 6

Это то, что я делал, чтобы обойти эту ошибку. В основном вы находите, где эта строка находится в базе данных на основе первичного ключа. Если он не существует, вы вставляете его. В противном случае вы получите версию из базы данных и обновите все необходимые поля.

public static void Update(Enquiry enquiry)
{
    JobsDataContext db = new JobsDataContext();

    var enquiries = from e in db.Enquiries
                    where e.PKID == enquiry.PKID
                    select e;

    if (enquiries.Count() < 1)
    {
        db.Enquiries.InsertOnSubmit(enquiry);
    }
    else
    {
        Enquiry updateEnquiry = enquiries.Single();

        updateEnquiry.LengthMm = enquiry.LengthMm;
        updateEnquiry.ShippedQty = enquiry.ShippedQty;
        updateEnquiry.StatusCode = enquiry.StatusCode;
    }

    db.SubmitChanges();
}

Это может стать утомительным, если вы постоянно обновляете свою схему базы данных, так как вам нужно вернуться сюда, чтобы обновить код.

Ответ 7

попробуйте это, даже если ваш идентификатор TEntity (здесь Area) - столбец Identifier; Только это, без каких-либо изменений в вашей SP или модели:

public void InitForm()
{
    bnsEntity.DataSource = CacheManagement.cachedAreas;
    newID = CacheManagement.cachedAreas.LastOrDefault().areaID + 1;
    grdEntity.DataSource = bnsEntity;
}

private void tsbNew_Click(object sender, EventArgs e)
{
    var newArea = new Area();
    newArea.areaID = (byte)newID++;
    dataContext.GetTable<Area>().InsertOnSubmit(newArea);
    bnsEntity.Add(newArea);
    grdEntity.MoveToNewRecord();
}

Ответ 8

У меня есть аналогичный подход к Noah's, но я использую хранимую процедуру, чтобы проверить, существует ли запись с этим PK, таким образом, объект не загружается в контексте, а код обновления включает только две строки кода и не потребует изменений в будущем при добавлении/удалении полей из таблицы, потребуется изменить SP только в случае изменения PK таблицы:

bool existe = Convert.ToBoolean(dbc.spSConfigReportesPeriodicos(configReportesPeriodicos.CodigoCliente));

if (existe)
{
    dbc.ConfigReportesPeriodicos.Attach(configReportesPeriodicos);
    dbc.Refresh(RefreshMode.KeepCurrentValues, configReportesPeriodicos);
}
else
{
    dbc.ConfigReportesPeriodicos.InsertOnSubmit(configReportesPeriodicos);
}
dbc.SubmitChanges();

И вот хранимая процедура:

ALTER PROCEDURE dbo.spSConfigReportesPeriodicos
(
    @codigoCliente int
)
AS

IF EXISTS(SELECT 1 FROM dbo.ConfigReportesPeriodicos WHERE CodigoCliente = @codigoCliente)
    RETURN 1
ELSE
    RETURN 0

RETURN

Ответ 9

Вам не нужно делать такую ​​проверку, чтобы увидеть, нужно ли вам использовать Updates или Inserts - для Linq для выполнения!

Вот пример из проекта, над которым я работаю (извините его в VB.Net:)), который демонстрирует, как это решить.

Код еще не оптимизирован и довольно уродлив, но он имеет смысл. Вы можете игнорировать бит, где он извлекает значения из checkboxlist - это просто показывает, как вы можете обновлять дочерние сущности.

Здесь используется метод OnUpdating, который включает обновление (это усеченный код):

Protected Sub LinqDataSource22_Updating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.LinqDataSourceUpdateEventArgs) Handles LinqDataSource22.Updating

            ' The main entity
            Dim updatedObject As FeedbackDraft = e.NewObject

            updatedObject.Modified = DateTime.Now
            updatedObject.ModifiedBy = UserHelper.GetCurrentUserName

            ' Example: Modify the updated object
            Dim aList As RadioButtonList = FeedbackFormView.FindControl("MyRadioButtonList")
            If aList IsNot Nothing AndAlso Not String.IsNullOrEmpty(aList.SelectedValue) Then
                updatedObject.aProperty = aList.SelectedValue
            End If


            ' Main context - for updating parent entity
            Using ctx As New CustomDataContext()

                ' Example: ... more modification of the main entity
                updatedObject.Status = "Draft"

                ' Deal with child items
                ' Secondary context - for checking against existing data in DB and removing items that have been unselected in the form
                Using ctx2 As New CustomDataContext()

                    ' We need to pull the record from the database to get the full constructed object graph
                    ' This method does a linq query to retrieve the FeedbackDraft object by ID
                    Dim originalObject As FeedbackDraft = GetOriginalFeedbackDraft(ctx2, updatedObject.FeedbackId)

                    ' ... truncated ...

                    ' Loop through CheckBoxList items and updated our entity graph
                    For Each li As ListItem In cbList.Items

                        ' ... code to work with ListItem truncated ...

                        Dim c As New ChildObject()
                        updatedObject.ChildObjects.Add(c)
                        ' Set the child collection to insert - this is using the main context
                        ctx.ChildObjects.InsertOnSubmit(c)


                        ' We can also delete things using the secondary context
                        Dim o as OtherChildObject()
                        o = GetOtherChildObjectById(updatedObject.FeedbackId)
                        ctx2.OtherChildObjects.DeleteOnSubmit(o)
                        ctx2.SubmitChanges()

                    Next
                End Using

                ' You can do further child object updates here...

                ' Now, attach main object for update
                ctx.PartnerFeedbackDrafts.Attach(updatedObject, e.OriginalObject)
                ctx.SubmitChanges()

            End Using

            e.Cancel = True

        End Sub

Ответ 10

У меня возникла эта проблема после выбора строки из базы данных с помощью первичного ключа, например "BOB". Затем я усекаю таблицу с помощью dc.ExecuteCommand("TRUNCATE TABLE ShippingReport"); и делаю SubmitChanges(), думая, что это избавится от поля, и я смогу вставить другой с тем же ключом, но при попытке вставить ошибку при ошибке. Просто нужно было сделать dc = new DataContext(); после первого SubmitChanges и это исправило его для меня, поскольку этот объект все еще существовал в DataContext, что в основном говорит ответ bruno conde.

Ответ 11

В моем случае это произошло в ситуации, когда я получил запись, а затем попытался обновить запись новой записью. Мозг может сказать, что все это происходит.: Р

public void UpdateEntry(Entity entity)
{
    var oldEntry = select ....
    var updatedEntity = new Entity{...}; // mix of entity and oldEntry

    _repository.Update<Entity>(updatedEntity);
}

становится

public void UpdateEntry(Entity entity)
{
    var oldEntry = select ....

    oldEntry.CreationDate = entity.CreationDate {...}

    _repository.Update<Entity>(oldEntry);
}