我正在尝试使用复合主键创建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的结果中。所以,我知道开始搜索的方向,至少。
答案 0 :(得分: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();
答案 1 :(得分: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,应该是。这个不正确的数据导致为aspnet_Users表创建的跟踪表的结构不正确,因此,只需在scope_config表中修复xml就不足以解决问题。所以,看起来我偶然发现了一个非常大的问题,需要一些工作才能纠正。我不认为我正在做任何事情来创建此错误,因为我在执行服务器配置时没有设置任何参数。
我无法在其他任何地方找到这个问题的描述,我发现这很奇怪,但我会继续寻找。
唉!
我将在SQL Server Management Studio中包含来自资源管理器的图像。
感谢JuneT,您愿意提供帮助。
答案 2 :(得分:0)
这看起来是由于DataReader的GetSchemaTable,它由Sync 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;