我有一个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();
}
这种方法通常可以正常工作,但过了一段时间后我收到错误“无法添加一个已经在使用的密钥的实体”。
答案 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);
}