0

我正在尝试为具有复合主键的表创建 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);
Collection<string> parentkeys = new Collection<string>();
parentkeys.Add("UserId"); 
Collection<string> childkeys = new Collection<string>();
childkeys.Add("RoleId");
childkeys.Add("UserId");
tableDesc.Constraints.Add(new DbSyncForeignKeyConstraint("FK_UsersRoles_Users", "Users", "UsersRoles", parentkeys, childkeys));

上面的代码会产生这个错误:

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

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

所以我有点不清楚我应该如何做到这一点。在此示例中,约束实际上应该仅与 UserId 列有关。但是,由于 UsersRoles 表有一个复合主键,我应该在约束中包含它吗?如果我在约束定义中遗漏了“RoleId”,我会得到一个错误......如果我包含它,我会得到一个不同的错误。

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

编辑附加信息:好的。问题似乎与 DBSyncForeignKeyConstraint 创建无关。问题似乎与 GetDescriptionForTable 功能有关。它似乎没有将 UserId 作为主键。在我的项目中,我实际上正在使用一个使用 aspnet_Membership 模式的数据库。因此,如果我编写 aspnet_Users 表的脚本,它看起来像这样: ' CREATE TABLE [dbo].[aspnet_Users](
[ApplicationId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NOT NULL,
[UserName] nvarchar NOT NULL,
[LoweredUserName] nvarchar NOT NULL,
[MobileAlias] nvarchar NULL,
[IsAnonymous] [bit] NOT NULL,
[LastActivityDate] [datetime] NOT NULL, PRIMARY KEY NONCLUSTERED ( [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]

GO

ALTER TABLE [dbo].[aspnet_Users] WITH CHECK ADD FOREIGN KEY([ApplicationId]) REFERENCES [dbo].[aspnet_Applications] ([ApplicationId]) GO
ALTER TABLE [dbo].[aspnet_Users] ADD DEFAULT (newid()) FOR [UserId]
GO
ALTER TABLE [dbo].[aspnet_Users] ADD DEFAULT (NULL) FOR [MobileAlias]
GO
ALTER TABLE [dbo] [aspnet_Users] ADD DEFAULT ((0)) FOR [IsAnonymous] GO'

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

4

3 回答 3

0

不知道你是如何配置代码的,但这工作得很好

        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();
于 2012-09-22T03:00:41.883 回答
0

好的,这似乎是范围配置功能的一个非常严重的问题。如果我转到已配置的源数据库,并查看 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,而它们不是。并且,UserId 列没有标记为 pk,但它应该标记为 pk。这种不正确的数据会导致为 aspnet_Users 表创建的跟踪表的结构不正确,因此,仅修复 scope_config 表中的 xml 不足以解决问题。所以,看起来我偶然发现了一个相当大的问题,需要一些工作来纠正。我认为我没有做任何事情来创建此错误,因为我在执行服务器配置时没有设置任何参数。

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

啊!

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

感谢您,JuneT,您愿意提供帮助。

在此处输入图像描述

于 2012-09-23T18:20:02.987 回答
0

这看起来是由于 Sync Fx 在内部使用 DataReader 的 GetSchemaTable 来获取表结构(请参阅:http ://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/c1c113e2-32dc-4826- b6e0-17dff29c1baf )

作为一种解决方法,只需自己设置PK。

例如,

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;
于 2012-09-26T01:58:39.830 回答