2009-01-07 61 views
16

我有一个LINQ2SQL设置,将对象从客户端发送(柔性通过flourinefx)添加一个实体,并将其附加到新的DataContext低于看出:LINQ2SQL:不能用钥匙已在使用

我还有一个在整个会话中使用的“全局”数据上下文。

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


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

     db.SubmitChanges(); 
    } 

这种方法通常工作正常,但过了一段时间我得到的错误“无法用钥匙已在使用添加实体”。

+2

这可能是我已经在LINQ还没有看到最少的描述性错误。啊。 SQL在这种情况下给出了一个更好的错误?哇。 – jcollum 2010-12-17 22:22:21

回答

9

我想这个错误发生在Attach实体到已经加载的DataContext

导致该错误代码是完全一样告诉你这里?在创建新的OffertaDataContext之后,您是否在Attach之前查询任何内容?

+2

是的,我喜欢。我从数据库中提取旧记录以检查新的一些属性,并且使用了相同的DataContext。我用两个sepparate使用子句解决了。 – 2009-01-07 23:10:18

3

你是否试图添加多个新对象的LinqEntities正在创建一个键0?

我在过去曾经遇到过这个问题,当我试图将项目添加到我的页面上的表格中,然后当我试图删除或更新这些项目时,倍数将会有关键字0。如何处理我的请求......

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

如果您更新数据库架构所有的时间这可能成为繁琐的,因为你必须回到这里来更新代码。

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

这可能不是你的问题(我不知道),但它是我的,因为人们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)> 
40

我得到这个错误,那是因为我忘了设置在数据库中“标识规范”(自动递增)主键字段。当我改变这个时,我很好。卫生署!

+0

如果您无法修改数据库,该怎么办? – 2015-12-23 13:00:55

3

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

+1

是。我希望他们只是说“尝试插入重复的主键” – 2012-10-20 20:59:48

0

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

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