2011-01-18 5 views
-1

現在のプロジェクトでは、SQL Server 2008、visual studio 2008、linq、ado.netを使用しています。このプロジェクトはWebとデスクトップで実装されています。identity_insertと同期の問題

私の問題は、Web DBとデスクトップDBの間のデータの同期です。ここ

同期は以下の通りです:クライアントに挿入

  1. 新しいデータがサーバーに同期されます。
  2. クライアントの更新されたデータがサーバーに同期されます。

ここで私のテーブル構造を見せてください。

私たちは私のテーブル名がフィールド

顧客
...................
customerno、BIGINT、主キーと "顧客" であると仮定してみましょう、nullでない、アイデンティティ真(1から始まる)
FIRSTNAME、...
姓、...

今私は、クライアントで同じテーブルを持っていますが、主キーのIDが20000本を開始します主キーの識別情報は、クライアントシステムの数によって異なります。テーブルに1枚のレコードと

サーバがcustomerno 1から始まる=次のシナリオを考えてみましょう
CLIENT1 = customernoテーブル内の2つのレコードで、20000で始まる
クライアント2 = customernoテーブル

に3つのレコードを、30000で始まります

今私は、LINQのdoesntのサポートIDENTITY_INSERT、イム使用してado.netとして、次のコード

 cmd.CommandText = "set identity_insert " + tableName + " on"; 
     cmd.ExecuteNonQuery(); 

     foreach (string query in this.queries) 
     { 
      cmd.CommandText = query; // this is my insert query 
      cmd.ExecuteNonQuery(); 
     } 

     cmd.CommandText = "set identity_insert " + tableName + " off"; 
     cmd.ExecuteNonQuery(); 

を使用して、CLIENT1で同期を押すと

私のコードでは、最初にidentity_insertをオンに設定し、データを挿入し、最後にidentity_insertをオフに設定します。

ここで私の問題は、データがclient1、 から同期され、2つのレコードが20001,20002というcustomernoを持つサーバーに挿入されたことです。 http://msdn.microsoft.com/en-us/library/ms188059.aspx

サーバにおけるcustomernoカラムの同一の通り

は(この場合には20002となる)最大値に設定されています。私は、サーバーにデータを挿入する際

は今、それは私が最大値を取るために、サーバーのID列をたくないここ20003.

としてcustomernoを挿入します。

上記のように考えると、同期する前にサーバーに1レコードあり、そのIDは1であるため、1つまたは複数のクライアントと同期した後、サーバーの次のID(customerno)サーバーに新しく挿入されたデータの場合は3,4 .....となります。

ここでは、任意の時点で任意のクライアントがサーバーとデータを同期できます。

答えて

3

2つのフィールドに1つのフィールドを使用しています。顧客を一意に識別し、情報源を把握する。

プライマリキーとしてuniqueidentifierを使用し、別のフィールドを使用して情報のソースを判断できます。

主キーのデフォルトの制約としてnewid()を使用します。レプリケートするときは、使用するGUIDを指定します。これはnewid()の代わりに使用されます。

編集1

トラブルあなたの主キーを交換をお持ちの場合は、候補キーとしてGUID列を追加することができます。この問題は、Customersテーブルとの関係を持つテーブルを更新する必要がある場合、サーバー間でデータをレプリケートするロジックがさらに複雑になります。最初にすべてのCustomersを挿入してから、Customersテーブルを照会して、関連するテーブルで使用するFK CustomerIDを把握する必要があります。

+0

GUIDが良好な新しい列を使用しています。私のデータベースのすべてのテーブルを変更する必要があります。 – Harsha

+0

データベースの –

2

あなたは非常に悪い場所にいます。サロゲート・キーの範囲を割り当てる場合は、ID列を使用できません。これを放棄し、組み込まれたreplication技術と一緒に行くのはおそらく正しいことですか?

正しいことができない場合は、ID列を削除してintにすることができます。その後、独自の自動インクリメントアルゴリズムを作成することができますが、競合状態に注意してください(つまり、MAXは使用しないでください)。

0

私は思っています。私はこれが最良のアイデアだとは示唆していませんが、私が見る限り、同期中にすべてのデータ変更をブロックすることで、以下のことが機能することがわかります。クライアントの可能な最大数と各ソースからの挿入の最大数を正確に予測する必要があるという点では、アプローチ自体に固有の問題があることは明らかです。

create table dbo.t (id int identity(1,1) primary key) 

INSERT INTO dbo.t DEFAULT VALUES 
INSERT INTO dbo.t DEFAULT VALUES 
INSERT INTO dbo.t DEFAULT VALUES 




--Do the Synch 
BEGIN TRAN 

DECLARE @MaxId int = (SELECT MAX(id) FROM t WITH (TABLOCK, REPEATABLEREAD) WHERE id<20000) 
         --Take a shared table lock to prevent any concurrent modifications 

SET IDENTITY_INSERT t ON 
INSERT INTO t(id) VALUES (20000) 
SET IDENTITY_INSERT t OFF 

DBCC CHECKIDENT ("dbo.t", RESEED, @MaxId) 

COMMIT 
--Synch Finished 

INSERT INTO dbo.t DEFAULT VALUES /*Will have the value 4*/ 
SELECT * FROM dbo.t 


DROP table dbo.t 
+0

にあるCustomersに関連するすべてのテーブルを変更すると問題が発生した場合の編集済みの回答ですが、テーブルを再シードすることはできますか?他の人はidentity_insertを使わずにデータを挿入します。 – Harsha

+0

@Harsha - それを行う唯一の方法は、同期中に同時挿入をブロックすることではありません。それ以外の場合は、現在のシードより大きなIDを持つレコードを挿入するとすぐに、シードが増加し、これらの同時挿入が新しいシード値を使用して終了すると思います。この並行性の欠如が受け入れられない場合は、他の回答で提案されているようにスキーマを変更する必要があります。 –