2009-04-07 2 views
5

Ich muss regelmäßig Daten in meine SQL Server-Datenbank einfügen. Aber die Feeds, wo ich die Daten lese, wiederholen einige Daten, die zuvor eingefügt wurden. Wenn ich Linq-to-SQL verwende, um in die Datenbank einzufügen, werden entweder einige Daten dupliziert oder eine Primärschlüsselverletzung wird ausgelöst, abhängig vom Primärschlüssel.Wie fügt man nur neue Datensätze mit Linq-to-SQL ein?

Wie fügen Sie die Daten ohne Doppelungen und ohne Ausnahmen ein? Ich möchte die Ausnahme nicht mit einem try-catch vermeiden, da nach dem Auslösen der Ausnahme der Rest der Daten nicht eingefügt wird.

Update fand ich auch meine eigene Lösung: Ich habe eine duplizierte Einträge Löschung gespeicherte Prozedur geschrieben, die direkt nach der SubmitChanges InsertAllOnSubmit + ausgeführt wird

Antwort

6

Alles, was Sie tun müssen, ist eine neue Instanz der Klasse zu erstellen und dann rufen InsertOnSumbit() auf dem Tisch:

var foo = new MyFoo { Name = "foo1" }; 
var dc = new MyDataContext(); 
dc.Foos.InsertOnSubmit(foo); 
dc.SubmitChanges(); 

die andere Sache, die Sie sicher sein müssen, ist, wie Sie Ihre ID-Spalte sind erhöht wird. Im Allgemeinen stelle ich immer sicher, dass ich die IDENTITY (1,1) -Einstellung für meine ID-Spalten verwende. Dies wird auf Ihrer LINQ Unternehmens-ID-Spalte erklärt wie folgt:

[Column(AutoSync = AutoSync.OnInsert, IsPrimaryKey = true, IsDbGenerated = true)] 
public Int32 Id { get; set; } 

Um Duplikate zu vermeiden, was Sie wirklich brauchen, ist, was wir in meinem Geschäft nennen eine „anhängen“ -Funktionalität. IMHO ist dies am einfachsten mit einer gespeicherten Prozedur ausgeführt - wir sogar eine Vorlage haben wir dafür verwenden:

USE [<Database_Name, sysobject, Database_Name>] 
GO 

CREATE PROCEDURE [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>__append] 
(
    @id INT OUTPUT, 
    @<Key_Param, sysobject, Key_Param> <Key_Param_Type, sysobject, VARCHAR(50)> 
) 
AS 
BEGIN 

     SELECT @id = [id] FROM [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s] (NOLOCK) WHERE [<Key_Param, sysobject, Key_Param>] = @<Key_Param, sysobject, Key_Param> 

IF @id IS NULL 
BEGIN  
    INSERT INTO [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s] ([<Key_Param, sysobject, Key_Param>]) 
    OUTPUT INSERTED.[id] INTO @inserted_ids 
    VALUES (@<Key_Param, sysobject, Key_Param>) 

    SELECT TOP 1 @id = [id] FROM @inserted_ids; 
END 
ELSE 
BEGIN 
    UPDATE [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s] 
    SET 
     [<Key_Param, sysobject, Key_Param>] = @<Key_Param, sysobject, Key_Param> 
    WHERE [id] = @id 
END 
END 
GO 

Es ist möglich, es in Linq zu tun, obwohl, fragt nur für eine Liste der vorhandenen IDs (oder was auch immer Spalte Sie Keying off von):

var dc = new MyDataContext(); 
var existingFoos = dc.Foos.ToList(); 
var newFoos = new List<Foo>(); 
foreach(var bar in whateverYoureIterating) { 
// logic to add to newFoos 
} 
var foosToInsert = newFoos.Where(newFoo => !existingFoos.Any(existingFoo => newFoo.Id == existingFoo.Id)); 

dc.Foos.InsertAllOnSubmit(foosToInsert); 
dc.SubmitChanges(); 
// use the next line if you plan on re-using existingFoos. If that's the case I'd wrap dc.SubmitChanges() in a try-catch as well. 
existingFoos.AddRange(foosToInsert); 
+0

warten auf Ihre Bearbeitung ... –

+0

Die LINQ-Lösung scheint ziemlich langsam. Die Abfrage eines riesigen Tisches und das Laden der Inhalte in den Speicher scheint für mich undurchführbar. Vielleicht sollte ich beim SP-Ansatz bleiben. –

+1

Das ist, was ich dachte ... Obwohl, Sie könnten die LINQ-Lösung beschleunigen, indem Sie nur die Eigenschaften auswählen, die Sie wirklich brauchen ... zum Beispiel nur die ID-Spalte. Wenn Sie die "vorhandene" Abfrage für mehrere Durchläufe erneut verwenden können, wird das ebenfalls hilfreich sein. –

1

Leider gibt es keinen Weg, um es als Linq to SQL die Datenbank nicht überprüft, bevor es in den Einsatz durchführt. Die einzige Möglichkeit, dies zu tun, besteht darin, die Datenbank zuerst abzufragen, um festzustellen, ob der doppelte Datensatz existiert, und den Datensatz dann hinzuzufügen, wenn dies nicht der Fall ist.

Idealerweise unterstützt Linq to SQL die Eigenschaft Ignore Duplicate Keys in einer SQL-Spalte. Aber leider tut es das momentan nicht.

Verwandte Themen