2012-09-19 103 views
0

我想创建一个具有复合主键的表的DbSyncForeignKeyConstraint,但是,我不断收到错误。下面是一些示例代码,以证明我在做什么:如何创建一个具有复合主键的表的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)); 

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

The definition of referring columns (such as number of columns or data types) in referential relationships must match the referred columns.

如果我用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”的结果,我看到“LoweredUserName”被列为PKColumns列“的applicationID”和和UserId列在NonPkColumns中。我不知道是什么导致了这一点。但是,至少我明白为什么错误告诉我列“UserId”不在主键中。它在数据库中,但它不在GetScopDescription的结果中。所以,至少我知道开始搜索的方向。

+0

感谢编辑...我不知道为什么代码没有正确格式化。我多次尝试使它看起来不错。 – rogdawg

回答

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

令人惊叹。我可以在我使用的代码和我提供的示例(为了清楚起见)之间唯一的区别是,Users表中的主键在我的真实代码中是非聚集的,并且聚集在上面的示例代码中。我有几个实例在创建一个非集群主键的外键约束,所以我并不认为这是问题所在。在我的实际代码中,我尝试使用aspnet_Membership模式同步到数据库,并且此约束位于aspnet_UsersInRoles和aspnet_Users(也是aspnet_UsersInRoles和aspent_Roles)之间。我会继续尝试。 – rogdawg

+0

顺便说一下,我使用Sync Framework 2.1 – rogdawg

+0

请在“编辑其他信息:确定”后看到我的原始帖子。谢谢。 – rogdawg

0

OK,这似乎是与范围供应功能一个相当严重的问题。如果我去到已置备我的源数据库,并期待在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。这个不正确的数据会导致为aspnet_Users表创建的跟踪表的结构不正确,因此,仅仅修复scope_config表中的xml不足以解决问题。所以,看起来我已经偶然发现了一个很大的问题,需要一些工作来纠正。我不认为我正在做任何事情来创建此错误,因为在执行服务器配置时我没有设置任何参数。

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

呃!

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

谢谢JuneT,感谢您的帮助。

enter image description here

0

这看起来像由于DataReader的的的GetSchemaTable在内部使用的同步Fx的抢表结构(参见: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; 
相关问题