2009-04-07 7 views
5

SQL Serverデータベースに定期的にデータを挿入する必要があります。しかし、私がデータを読むフィードは、以前に挿入されたデータを繰り返します。 DBに挿入するためにLinq-to-SQLを使用すると、主キーに応じてデータの一部が複製されるか、主キー違反例外が発生します。Linq-to-SQLを使用して新しいレコードのみを挿入する方法は?

重複なしで例外なくデータを挿入するにはどうすればよいですか?例外が発生すると残りのデータは挿入されないため、try-catchで例外を回避する必要はありません。

更新私も自分自身の解決策を見つけた:私はあなたがしなければならないのは、あなたのクラスの新しいインスタンスを作成している右InsertAllOnSubmit +でSubmitChanges

答えて

6

後に実行され、重複エントリの削除ストアドプロシージャを、書き、

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

あなたのID列をどのように増分しているかを確認する必要があります。これは、テーブルのInsertOnSumbit()を呼び出すことです。一般的に、私は自分のID列に必ずIDENTITY(1,1)設定を使用するようにします。これがそうのようなあなたのLINQのエンティティのid列に宣言されています:

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

重複を避けるために、あなたが本当に必要なものを私たちは機能「を追加」私の店で呼んでいます。私見では、これが最も簡単にストアドプロシージャを用いて達成される - 私たちも、私たちはそれに使用するテンプレートを持っている:

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 

しかしLINQでそれを行うだけで、既存のIDのリストを照会することが可能である(または何あなたがのキーイングオフしているコラム):それは挿入を実行する前に、LINQ to SQLのデータベースをチェックしないよう

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

あなたの編集を待っています... –

+0

LINQソリューションはかなり遅いようです。巨大なテーブルを照会すると、メモリ内の内容を読み込むことができないようです。たぶん私はSPのアプローチに固執すべきです。 –

+1

それは私が想像したことです...しかし、あなたは本当に必要なプロパティを選択するだけで、LINQの解決をスピードアップすることができます...例えば、ID列だけです。また、複数の実行に対して「既存の」クエリを再利用できる場合は、同様に役立ちます。 –

1

は残念ながら、その周りに方法はありません。これを行う唯一の方法は、データベースに最初にを照会して、重複レコードが存在するかどうかを判断し、重複レコードが存在しない場合はレコードを追加することです。

Linq to SQLは、理想的にはSQLカラムのIgnore Duplicate Keysプロパティをサポートします。しかし残念ながら、それは現時点ではありません。

関連する問題