2009-01-07 3 views
16

Ich habe eine linq2sql Setup, wo Objekte von Client-Seite gesendet (flex über flourinefx) und sie an einen neuen Datacontext eines unten zu sehen:linq2sql: Kann nicht eine Einheit mit einem Schlüssel hinzufügen, die bereits in Gebrauch ist

I haben auch einen "globalen" Datenkontext, der während der gesamten Sitzung verwendet wird.

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


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

     db.SubmitChanges(); 
    } 

Dieser Ansatz funktioniert in der Regel gut, aber nach einer Weile erhalte ich die Fehlermeldung „Kann nicht eine Einheit mit einem Schlüssel hinzufügen, die bereits in Verwendung ist“.

+2

Dies möglicherweise der deskriptiven Fehler ist, dass ich noch in LINQ gesehen habe. Pfui. SQL gibt einen besseren Fehler in diesem Fall? Beeindruckend. – jcollum

Antwort

9

Ich denke, dieser Fehler passiert, wenn Sie Attach eine Einheit zu einem DataContext, die bereits geladen wurde.

Der Code, der den Fehler verursacht, ist genau wie Sie hier zeigen? Nach dem Erstellen der neuen OffertaDataContext Fragen Sie alles vor der Attach?

+2

Ja, das tue ich. Ich hatte den alten Datensatz aus der Datenbank abgerufen, um nach einigen Eigenschaften des neuen zu suchen, und ich verwendete denselben DataContext. Ich habe mit zwei sepparate using Klauseln gelöst. –

3

Versuchen Sie, mehrere neue Objekte in einem Treffer hinzuzufügen, wo die LinqEntities mit einem Schlüssel von 0 erstellt werden?

Ich hatte dieses Problem in der Vergangenheit, als ich versuchte, Elemente in eine Tabelle auf meiner Seite hinzuzufügen, und wenn ich dann versuchte, diese Elemente zu löschen oder zu aktualisieren, würde Vielfache den Schlüssel 0 haben. So offensichtlich wusste es nicht was mit meinen Anfragen zu tun ist ...

2

Dies ist, was ich getan habe, um diesen Fehler zu umgehen. Grundsätzlich finden Sie anhand eines Primärschlüssels, wo sich diese Zeile in der Datenbank befindet. Wenn es nicht existiert, fügen Sie es ein. Andernfalls erhalten Sie die Version aus der Datenbank und aktualisieren alle erforderlichen Felder.

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

Dies kann langweilig werden, wenn Sie Updates für Ihre Datenbank-Schema die ganze Zeit machen, wie Sie hierher kommen müssen kommen wieder den Code zu aktualisieren.

0

versuchen Sie dies, auch wenn Ihre TEntity (hier Area) ID ist eine Identifier-Spalte; Gerade sie, ohne jede Änderung Ihrer SP oder Modell:

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

Ich habe ein ähnliches aproach zu Noah, aber ich verwende eine gespeicherte Prozedur, um zu überprüfen, ob ein Datensatz mit dieser PK vorhanden ist oder nicht, auf diese Weise der Entity wird nicht in den Kontext geladen, und der Aktualisierungscode umfasst nur zwei Codezeilen und erfordert keine Änderungen in der Zukunft, wenn Sie Felder aus der Tabelle hinzufügen/entfernen. Der SP muss nur dann geändert werden, wenn sich der PK der Tabelle ändert:

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

Und hier ist die gespeicherte Prozedur:

ALTER PROCEDURE dbo.spSConfigReportesPeriodicos 
(
    @codigoCliente int 
) 
AS 

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

RETURN 
0

Sie sollten diese Art der Überprüfung nicht durchführen müssen, um zu sehen, ob Sie Updates oder Inserts benötigen - das ist für Linq zu tun!

Hier ist ein Beispiel aus einem Projekt, an dem ich gerade arbeite (tut mir leid, es ist in VB.Net :)), das zeigt, wie man das löst.

Der Code ist noch nicht optimiert und ziemlich hässlich - aber es bringt den Punkt über. Sie können das Bit ignorieren, indem es Werte aus der Checkbox-Liste abruft - das zeigt nur, wie Sie untergeordnete Entitäten aktualisieren können.

Hier ist die OnUpdating Methode, die das Update umfasst (dies ist verkürztes Code):

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

Dies könnte nicht Ihr Problem sein (kann ich nicht sagen), aber es war mir, und wie die Menschen diese Google Es könnte jemand anderem helfen. Wenn Sie nicht den integrierten Linq-to-SQL-Designer oder SQLMetal verwenden, um Ihre Linq-zu-SQL-Klassen zu generieren, oder wenn Sie vergessen haben, Ihre ID-Spalte zu IDENTITY zu machen, fehlt möglicherweise eine Eigenschaft Ihrer Spalte Attribut namens "IsDbGenerated". Achten Sie darauf, Ihre Spalte Attribut etwas wie folgt aussieht:

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

ich diesen Fehler, und es war, weil ich das Primärschlüsselfeld in der Datenbank zu setzen vergessen hatte, zu „Identität Specification“ (Auto-Inkrement). Als ich das änderte, war ich gut. Do!

+0

Was ist, wenn Sie die Datenbank nicht ändern können? –

3

Wenn Sie mehrere Entitäten gleichzeitig einfügen, versuchen Sie möglicherweise, eine doppelte Entität in den aktuellen Datenkontext einzufügen. Ich weiß, das ist zu einfach, aber es ist mir selbst passiert.

+1

yup. Ich wünschte, sie hätten gerade gesagt "Versuch, doppelten Primärschlüssel einzufügen" –

0

Ich hatte dieses Problem nach der Auswahl einer Zeile aus der Datenbank mit dem Primärschlüssel von sagen "BOB". Dann würde ich die Tabelle mit dc.ExecuteCommand("TRUNCATE TABLE ShippingReport"); abschneiden und tun SubmitChanges(), denkend dieses würde das Feld loswerden und ich könnte ein anderes mit dem gleichen Schlüssel einfügen, aber ich habe den OPs Fehler, wenn er versucht, einzufügen. Ich musste einfach dc = new DataContext(); nach den ersten SubmitChanges tun und das reparierte es für mich, da dieses Objekt noch im DataContext existierte, was im Grunde die Antwort von bruno conde ist.

0

In meinem Fall passierte es in einer Situation, in der ich einen Eintrag abgerufen hatte und dann versuchte, den Eintrag mit einem neuen Eintrag zu aktualisieren. Brainfart könnte man sagen, diese Dinge passieren aber. : P

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

    _repository.Update<Entity>(updatedEntity); 
} 

Wird

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

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

    _repository.Update<Entity>(oldEntry); 
} 
Verwandte Themen