linq2sql:无法使用已在使用的密钥添加实体

时间:2009-01-07 15:26:49

标签: c# linq-to-sql

我有一个linq2sql设置,其中对象从客户端发送(通过flourinefx flex)并将它们附加到新的datacontext,如下所示:

我还有一个在整个会话期间使用的“全局”datacontext。

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


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

        db.SubmitChanges();
    }

这种方法通常可以正常工作,但过了一段时间后我收到错误“无法添加一个已经在使用的密钥的实体”。

11 个答案:

答案 0 :(得分:42)

我收到此错误是因为我忘记将数据库中的主键字段设置为“身份规范”(自动增量)。当我改变这个时,我很好。卫生署!

答案 1 :(得分:9)

我认为如果您Attach 实体已经加载了DataContext,就会发生此错误。

导致错误的代码与您在此处显示的完全相同?创建新OffertaDataContext后,您是否在Attach之前查询了什么?

答案 2 :(得分:4)

这可能不是你的问题(我无法分辨),但它是我的,而且人们谷歌这可能会帮助其他人。如果您没有使用内置的Linq-to-SQL设计器或SQLMetal来生成Linq-to-SQL类,或者如果您忘记将ID列设置为IDENTITY,则可能缺少列上的属性名为“IsDbGenerated”的属性。请确保您的列属性如下所示:

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

答案 3 :(得分:4)

如果您一次插入多个实体,可能只是尝试将重复的实体插入当前的datacontext。我知道这太简单了,但它恰好发生在我自己身上。

答案 4 :(得分:3)

您是否尝试在使用0键创建LinqEntities的匹配中添加多个新对象?

我过去遇到过这个问题,当时我试图将项目添加到我的页面上的表格中,然后当我尝试删除或更新这些项目时,倍数会有0键。所以显然它不知道是什么我的要求......

答案 5 :(得分:2)

这就是我为解决这个错误所做的工作。基本上,您可以根据主键找到数据库中此行的位置。如果它不存在则插入它。否则,您将从数据库中获取该版本并更新所有必需的字段。

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

如果您一直对数据库架构进行更新,这可能会变得乏味,因为您必须回到这里更新代码。

答案 6 :(得分:0)

即使您的TEntity(此处为区域)ID是标识符列,也请尝试此操作; 就是这样,你的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();
}

答案 7 :(得分:0)

我对诺亚有类似的方法,但我使用存储过程来验证是否存在具有该PK的记录,这样实体不会在上下文中加载,并且更新代码只涉及两行代码和当您从表中添加/删除字段时,将来不需要更改,只有在表的PK更改时才需要更改SP:

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

答案 8 :(得分:0)

您不应该进行那种检查,看看是否需要使用更新或插入 - 这是Linq要做的!

这是我正在研究的一个项目的例子(对不起,它在VB.Net :)),它演示了如何解决这个问题。

代码尚未经过优化且非常丑陋 - 但它得到了重点。您可以忽略从复选框列表中提取值的位 - 这只显示了如何更新子实体。

这是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

答案 9 :(得分:0)

我从数据库中选择了一个主键为'BOB'的行后出现此问题。然后我会用dc.ExecuteCommand("TRUNCATE TABLE ShippingReport");截断表并执行SubmitChanges(),认为这将摆脱该字段,我可以使用相同的密钥插入另一个,但我在尝试时遇到了OP的错误插入。只需在第一次SubmitChanges之后执行dc = new DataContext();并为我修复它,因为该对象仍然存在于DataContext中,这基本上就是bruno conde的答案所说的。

答案 10 :(得分:0)

在我的情况下,它发生在我检索了一个条目的情况下,然后尝试用新条目更新条目。 Brainfart可能会说,这些事情发生了。 :P

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