C# 如何为具有复合主键的表创建DbSyncForeignKeyConstraint

C# 如何为具有复合主键的表创建DbSyncForeignKeyConstraint,c#,sync,foreign-key-relationship,microsoft-sync-framework,C#,Sync,Foreign Key Relationship,Microsoft Sync Framework,我试图为一个具有复合主键的表创建一个DbSyncForeignKeyConstraint,但是,我不断得到错误。下面是一些示例代码来演示我所做的工作: 示例表: USE [TempTest] GO CREATE TABLE [dbo].[Users]( [UserId] [uniqueidentifier] NOT NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ( [UserId] ASC

我试图为一个具有复合主键的表创建一个DbSyncForeignKeyConstraint,但是,我不断得到错误。下面是一些示例代码来演示我所做的工作:

示例表:

USE [TempTest]
GO

CREATE TABLE [dbo].[Users](
        [UserId] [uniqueidentifier] NOT NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED 
    (
        [UserId] ASC
    )
    WITH 
    (
        PAD_INDEX  = OFF, 
        STATISTICS_NORECOMPUTE  = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS  = ON, 
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[UsersRoles](
    [UserId] [uniqueidentifier] NOT NULL,
    [RoleId] [uniqueidentifier] NOT NULL,
    CONSTRAINT [PK_UsersRoles] PRIMARY KEY CLUSTERED 
    (
        [UserId] ASC,
        [RoleId] ASC
    )
    WITH 
    (
        PAD_INDEX  = OFF, 
        STATISTICS_NORECOMPUTE  = OFF, 
        IGNORE_DUP_KEY = OFF, 
        ALLOW_ROW_LOCKS  = ON, 
        ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
) ON [PRIMARY]

GO
这是我的C代码:

DbSyncTableDescription tableDesc=SqlSyncDescriptionBuilder.GetDescriptionForTable(“UsersRoles”,(SqlConnection)this.dbProvider.Connection);
集合parentkeys=新集合();
parentkey.Add(“UserId”);
Collection childkeys=new Collection();
添加(“RoleId”);
添加(“用户ID”);
tableDesc.Constraints.Add(新的DbSyncForeignKeyConstraint(“FK_UsersRoles_Users”、“Users”、“UsersRoles”、parentkey、childkey));
上述代码将产生以下错误:

引用列的定义(例如列数或数据 引用关系中的类型)必须与引用列匹配

如果我用
childkeys.Add(“RoleId”)
注释掉该行,则会出现以下错误: “引用的表必须具有主键或候选键。”

所以我有点不清楚该怎么做。在本例中,约束实际上应该只与UserId列有关。但是,既然UsersRoles表有一个复合主键,我应该在约束中包含它吗?如果我在约束定义中省略了“RoleId”,我会得到一个错误……如果我包含它,我会得到一个不同的错误

有人对我应该如何进行有什么建议吗? (注:我有一段代码,可以在具有普通非复合主键的表之间创建其他外键,并且该代码可以正常工作)

使用其他信息编辑: 好啊问题似乎不在于DBSyncForeignKeyConstraint的创建。问题似乎出在GetDescriptionForTable功能上。它似乎没有将中的UserId作为主键。在我的项目中,我实际使用的是一个使用aspnet_成员模式的数据库。因此,如果我为aspnet_Users表编写脚本,它如下所示:
'
创建表[dbo]。[aspnet\U用户](
[ApplicationId][uniqueidentifier]不为空,
[UserId][uniqueidentifier]不为空,
[用户名]nvarchar不为空,
[LoweredUserName]nvarchar不为空,
[MobileAlias]nvarchar NULL,
[IsAnonymous][bit]不为空,
[LastActivityDate][datetime]不为空, 主键非聚集 ( [UserId]ASC )在[主]上打开(PAD\u INDEX=OFF,STATISTICS\u norecocomputer=OFF,IGNORE\u DUP\u KEY=OFF,ALLOW\u ROW\u LOCKS=ON,ALLOW\u PAGE\u LOCKS=ON) )在[小学]

通过选中添加外键([ApplicationId])更改表[dbo].[aspnet\U Users] 引用[dbo].[aspnet_应用程序]([ApplicationId]) 去
ALTER TABLE[dbo].[aspnet\u Users]为[UserId]添加默认值(newid())

ALTER TABLE[dbo].[aspnet\U Users]为[MobileAlias]添加默认值(NULL)

ALTER TABLE[dbo][aspnet_Users]为[IsAnonymous]GO'添加默认值((0))


但是,如果我检查调用“GetScopeDescription”的结果,我会看到列“ApplicationId”和“LoweredUserName”列作为PKColumns列出,而UserId列在非PKColumns列中。我不知道是什么原因造成的。但是,至少我理解了为什么错误告诉我“UserId”列不在主键中。它在数据库中,但在GetsCodeDescription的结果中不存在。所以,我至少知道应该从哪个方向开始搜索。

不确定您的配置代码是什么样子的,但这很好

        var sqlConn = new SqlConnection(@"Data Source=(local)\SQLExpress; Initial Catalog=Test; Integrated Security=True");
        var sqlConn2 = new SqlConnection(@"Data Source=(local)\SQLExpress; Initial Catalog=Test2; Integrated Security=True");

        var parent = SqlSyncDescriptionBuilder.GetDescriptionForTable("Users", sqlConn);
        var child = SqlSyncDescriptionBuilder.GetDescriptionForTable("UsersRoles", sqlConn);

        var parentPKColumns = new Collection<string> {"UserId"};
        var childFKColumns = new Collection<string> {"UserId"};

        child.Constraints.Add(new DbSyncForeignKeyConstraint("FK_UsersRoles_Users", "Users", "UsersRoles", parentPKColumns, childFKColumns));

        var fKTestScope= new DbSyncScopeDescription("FKTestScope");

        fKTestScope.Tables.Add(parent);
        fKTestScope.Tables.Add(child);

        var scopeProvisioning = new SqlSyncScopeProvisioning(sqlConn2, fKTestScope);

        scopeProvisioning.Apply();
var-sqlConn=new-SqlConnection(@“数据源=(本地)\SQLExpress;初始目录=测试;集成安全性=真”);
var sqlConn2=newsqlconnection(@“数据源=(本地)\SQLExpress;初始目录=Test2;集成安全性=True”);
var parent=SqlSyncDescriptionBuilder.GetDescriptionForTable(“用户”,sqlConn);
var child=SqlSyncDescriptionBuilder.GetDescriptionForTable(“UsersRoles”,sqlConn);
var parentPKColumns=新集合{“UserId”};
var childFKColumns=新集合{“UserId”};
添加(新的DbSyncForeignKeyConstraint(“FK_UsersRoles_Users”,“Users”,“UsersRoles”,parentPKColumns,childFKColumns));
var fKTestScope=new DbSyncScopeDescription(“fKTestScope”);
fKTestScope.Tables.Add(父级);
fKTestScope.Tables.Add(子级);
var scopeProvisioning=new-SqlSyncScopeProvisioning(sqlConn2,fKTestScope);
scopeProvisioning.Apply();

好的,这似乎是范围设置功能的一个非常严重的问题。如果我转到已设置的源数据库,并查看scope_config表的config_data列中的数据,我会发现xml中对aspnet_Users表的描述不正确:

  <Adapter Name="[aspnet_Users]" GlobalName="[aspnet_Users]" TrackingTable="[aspnet_Users_tracking]" SelChngProc="[aspnet_Users_selectchanges]" SelRowProc="[aspnet_Users_selectrow]" InsProc="[aspnet_Users_insert]" UpdProc="[aspnet_Users_update]" DelProc="[aspnet_Users_delete]" InsMetaProc="[aspnet_Users_insertmetadata]" UpdMetaProc="[aspnet_Users_updatemetadata]" DelMetaProc="[aspnet_Users_deletemetadata]" BulkTableType="[aspnet_Users_BulkType]" BulkInsProc="[aspnet_Users_bulkinsert]" BulkUpdProc="[aspnet_Users_bulkupdate]" BulkDelProc="[aspnet_Users_bulkdelete]" InsTrig="[aspnet_Users_insert_trigger]" UpdTrig="[aspnet_Users_update_trigger]" DelTrig="[aspnet_Users_delete_trigger]">
<Col name="ApplicationId" type="uniqueidentifier" param="@P_1" pk="true" />
<Col name="UserId" type="uniqueidentifier" param="@P_2" />
<Col name="UserName" type="nvarchar" size="256" param="@P_3" />
<Col name="LoweredUserName" type="nvarchar" size="256" param="@P_4" pk="true" />
<Col name="MobileAlias" type="nvarchar" size="16" null="true" param="@P_5" />
<Col name="IsAnonymous" type="bit" param="@P_6" />
<Col name="LastActivityDate" type="datetime" param="@P_7" />

您可以看到ApplicationId和LoweredUserName列被标记为pks,而不是pks。而且,UserId列没有标记为pk,而应该标记为pk。这种不正确的数据会导致为aspnet_Users表创建的跟踪表的结构不正确,因此,仅修复scope_config表中的xml不足以修复此问题。因此,我似乎偶然发现了一个相当大的问题,需要一些工作才能纠正。我认为我没有做任何事情来创建这个错误,因为我在执行服务器配置时没有设置任何参数

我在其他任何地方都找不到关于这个问题的描述,我觉得很奇怪,但我会继续寻找

我将在我的SQL Server Management Studio中包含一个来自资源管理器的图像

朱奈特,谢谢你愿意帮忙


这似乎是由于DataReader的GetSchemaTable,Sync Fx在内部使用它来获取表结构(请参阅:)

作为一个
  <Adapter Name="[aspnet_Users]" GlobalName="[aspnet_Users]" TrackingTable="[aspnet_Users_tracking]" SelChngProc="[aspnet_Users_selectchanges]" SelRowProc="[aspnet_Users_selectrow]" InsProc="[aspnet_Users_insert]" UpdProc="[aspnet_Users_update]" DelProc="[aspnet_Users_delete]" InsMetaProc="[aspnet_Users_insertmetadata]" UpdMetaProc="[aspnet_Users_updatemetadata]" DelMetaProc="[aspnet_Users_deletemetadata]" BulkTableType="[aspnet_Users_BulkType]" BulkInsProc="[aspnet_Users_bulkinsert]" BulkUpdProc="[aspnet_Users_bulkupdate]" BulkDelProc="[aspnet_Users_bulkdelete]" InsTrig="[aspnet_Users_insert_trigger]" UpdTrig="[aspnet_Users_update_trigger]" DelTrig="[aspnet_Users_delete_trigger]">
<Col name="ApplicationId" type="uniqueidentifier" param="@P_1" pk="true" />
<Col name="UserId" type="uniqueidentifier" param="@P_2" />
<Col name="UserName" type="nvarchar" size="256" param="@P_3" />
<Col name="LoweredUserName" type="nvarchar" size="256" param="@P_4" pk="true" />
<Col name="MobileAlias" type="nvarchar" size="16" null="true" param="@P_5" />
<Col name="IsAnonymous" type="bit" param="@P_6" />
<Col name="LastActivityDate" type="datetime" param="@P_7" />
downloadOnlyScopeDesc.Tables.Add(SqlSyncDescriptionBuilder.GetDescriptionForTable("aspnet_Users", (System.Data.SqlClient.SqlConnection)provider.Connection));

//untag wrong PK information
foreach(var pkColumn in downloadOnlyScopeDesc.Tables["aspnet_Users"].PkColumns)
{
    downloadOnlyScopeDesc.Tables["aspnet_Users"].Columns[pkColumn.QuotedName].IsPrimaryKey = false;
}

//tag the correct PK
downloadOnlyScopeDesc.Tables["aspnet_Users"].Columns["UserId"].IsPrimaryKey = true;