2009-04-07 14 views
5

Devo inserire alcuni dati periodicamente nel mio database SQL Server. Ma i feed in cui leggo i dati ripete alcuni dati che sono stati inseriti prima. Quando utilizzo Linq-to-SQL per inserire nel DB, alcuni dati vengono duplicati oppure viene sollevata un'eccezione di violazione della chiave primaria, a seconda della chiave primaria.Come inserire solo nuovi record usando Linq-to-SQL?

Come inserire i dati senza duplicazioni e senza eccezioni? Non voglio evitare l'eccezione con un try-catch, perché una volta sollevata l'eccezione il resto dei dati non viene inserito.

aggiornamento ho anche trovato la mia soluzione: ho scritto le voci duplicate eliminazione stored procedure, che viene eseguito subito dopo i InsertAllOnSubmit + SubmitChanges

risposta

6

Tutto quello che dovete fare è creare una nuova istanza della classe e quindi chiamare InsertOnSumbit() sul tavolo:

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

l'altra cosa che dovete essere sicuri di è come si sta incrementando la colonna ID. In generale, cerco sempre di utilizzare l'impostazione IDENTITY (1,1) sulle colonne ID. Questo è dichiarato sulla colonna id della vostra entità LINQ in questo modo:

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

Per evitare duplicati, che cosa si ha realmente bisogno è ciò che noi chiamiamo nel mio negozio un "aggiungere" la funzionalità. IMHO, questo è più facilmente realizzabile con una stored procedure - abbiamo anche un modello che usiamo per esso:

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 

E 'possibile farlo in LINQ, però, solo una query per un elenco di ID esistenti (o qualsiasi altra cosa colonna che si sta digitando off di):

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

in attesa di modifica ... –

+0

La soluzione LINQ sembra piuttosto lenta. Interrogare un tavolo gigante e caricare i contenuti in memoria mi sembra impossibile. Forse dovrei attenermi all'approccio SP. –

+1

Ecco cosa ho pensato ... Tuttavia, è possibile velocizzare la soluzione LINQ selezionando solo le proprietà di cui si ha realmente bisogno ... ad esempio, solo la colonna ID. Inoltre, se è possibile riutilizzare la query "esistente" per più esecuzioni, sarà altrettanto utile. –

1

Purtroppo, non c'è modo intorno ad esso come LINQ to SQL non controlla il database prima di eseguire l'inserto. L'unico modo per farlo è interrogare il database prima per determinare se il record duplicato esiste e quindi aggiungere il record se non lo fa.

Idealmente Linq to SQL supporta la proprietà Ignore Duplicate Keys su una colonna SQL. Ma sfortunatamente non è al momento.

Problemi correlati