identity_insert和同步问题

时间:2011-01-18 07:05:47

标签: c# .net sql synchronization

我在我当前的项目中使用SQL Server 2008,visual studio 2008,linq,ado.net。该项目在网络和桌面上实施。

现在我的问题是web db和桌面数据库之间的数据同步。

此处同步如下:

  1. 在客户端中插入的新数据将同步到服务器。
  2. 客户端中的更新数据已同步到服务器。
  3. 这里让我告诉你我的桌子结构。

    让我们假设我的表名是带有字段

    的“客户”

    客户
    ...................
    customerno,bigint,primary key,not null,identity true(从1开始)
    名字,...
    姓氏,......

    现在我将在客户端中拥有相同的表,但主键标识将以20000开头。此主键标识取决于客户端系统的数量。让我们考虑以下场景

    server = customerno从1开始,表中有1条记录 client1 = customerno以20000开头,表中有2条记录 client2 = customerno以30000开头,表中有3条记录

    现在当我在client1中按同步时,使用以下代码

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

    因为linq不支持identity_insert,即时通讯使用ado.net

    在我的代码中,首先设置identity_insert,插入数据,最后设置identity_insert。

    现在我的问题是,在从client1同步数据后, 两个记录插入到服务器中,customerno为20001,20002。

    根据http://msdn.microsoft.com/en-us/library/ms188059.aspx

    服务器中customerno列的标识设置为最大值(在这种情况下,它将是20002)。

    所以现在当我在服务器中插入数据时,它会将customerno作为20003插入。

    这里我不希望服务器标识列采用最大值。

    考虑到上述情况,在同步之前,我们在服务器中有1条记录,其id为1,所以在同步(与一个或多个客户端)之后,我希望服务器中的下一个id(customerno)为2,3 ,4 .....用于服务器中新插入的数据。

    此处任何客户端都可以在任何时间点与服务器同步数据。

3 个答案:

答案 0 :(得分:3)

您正在使用一个字段来完成两件事。唯一识别客户并找出信息来源。

您可以使用uniqueidentifier作为主键,并使用其他字段来确定信息来源。

使用newid()作为主键的默认约束。在复制时,指定要使用的GUID,将使用该GUID而不是newid()。

修改1

如果您在更换主键时遇到问题,可以将GUID列添加为候选键。那么问题是,如果您需要更新与Customers表有关系的表,那么在服务器之间复制数据的逻辑将会复杂得多。您必须首先插入所有客户,然后查询Customers表以确定您应在相关表中使用的FK CustomerID。

答案 1 :(得分:2)

你处在一个非常糟糕的地方。如果要分配代理键的范围,则不能使用标识列。放弃这一点并使用内置的replication技术可能是正确的事情。

如果你不能做正确的事情,你可以删除标识列并使其成为一个int。然后你可以创建自己的自动递增算法,但要注意竞争条件(即不要使用MAX)

答案 2 :(得分: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