我在两个SQL Server表之间有一个父子关系,带有一个多列外键。使用直接T-SQL,我可以按照预期在子表中插入一些外键列为null
的行。
但是,如果我尝试使用DataSet
和DataTable
执行此操作,则会获得InvalidConstraintException
(请参阅下面的示例)。我只遇到多部分键的这个问题;可以在没有InvalidConstraintException
的情况下插入具有单个空外键列的行。
我无法在ADO.NET上下文中找到有关此情况的任何信息。
问题:
-1
,而不是数据表中的null
,然后将这些null
写入数据库示例T-SQL代码(按预期运行没有错误):
CREATE TABLE [P](
[P1] [int] NOT NULL,
[P2] [int] NOT NULL,
PRIMARY KEY ([P1], [P2])
)
CREATE TABLE [C](
[C1] [int] NOT NULL,
[P1] [int] NOT NULL,
[P2] [int] NULL,
PRIMARY KEY ([C1] ASC)
)
ALTER TABLE [C] ADD CONSTRAINT [FK_C_P]
FOREIGN KEY([P1], [P2]) REFERENCES [dbo].[P] ([P1], [P2])
INSERT C (C1, P1, P2) VALUES (1, 1, NULL)
示例C#代码(从最后一行抛出的异常):
static void Main(string[] args)
{
var p = new DataTable("P");
var pp1 = new DataColumn("P1", typeof(int));
var pp2 = new DataColumn("P2", typeof(int));
p.Columns.AddRange(new[] { pp1, pp2 });
p.PrimaryKey = new[] { pp1, pp2 };
var c = new DataTable("C");
var cc1 = new DataColumn("C1", typeof(int));
var cp1 = new DataColumn("P1", typeof(int));
var cp2 = new DataColumn("P2", typeof(int));
c.Columns.AddRange(new[] { cc1, cp1, cp2 });
c.PrimaryKey = new[] { cc1 };
c.Constraints.Add(new ForeignKeyConstraint(new[] { pp1, pp2 }, new[] { cp1, cp2 }));
var s = new DataSet() { EnforceConstraints = true };
s.Tables.AddRange(new[] { p, c });
// the following throws InvalidConstraintException
c.Rows.Add(1, 1, null);
}
答案 0 :(得分:0)
您可以尝试使用
//nullable int?
而不是
int
你的钥匙类型?我不熟悉ADO.NET,但我对实体框架有类似的问题,这解决了我的问题。
答案 1 :(得分:0)
例如
答案 2 :(得分:0)
正如错误消息在运行程序时所说,“ForeignKeyConstraint Constraint2要求子键值(1,)存在于父表中。”那么你需要有一行包含这些值在p
。为此,您必须指定pp2
允许DBNull
值,并将行添加到p
。那是在
p.PrimaryKey = new[] { pp1, pp2 };
添加
pp2.AllowDBNull = true;
之前
c.Rows.Add(1, 1, null);
添加
p.Rows.Add(1, null);
这会将您发布的完整示例带到以下内容:
static void Main(string[] args)
{
var p = new DataTable("P");
var pp1 = new DataColumn("P1", typeof(int));
var pp2 = new DataColumn("P2", typeof(int));
pp2.DefaultValue = DBNull.Value;
p.Columns.AddRange(new[] { pp1, pp2 });
p.PrimaryKey = new[] { pp1, pp2 };
pp2.AllowDBNull = true;
var c = new DataTable("C");
var cc1 = new DataColumn("C1", typeof(int));
var cp1 = new DataColumn("P1", typeof(int));
var cp2 = new DataColumn("P2", typeof(int));
c.Columns.AddRange(new[] { cc1, cp1, cp2 });
c.PrimaryKey = new[] { cc1 };
c.Constraints.Add(new ForeignKeyConstraint(new[] { pp1, pp2 }, new[] { cp1, cp2 }));
var s = new DataSet() { EnforceConstraints = true };
s.Tables.AddRange(new[] { p, c });
// the following no longer throws InvalidConstraintException
p.Rows.Add(1, null);
c.Rows.Add(1, 1, null);
}
编辑:正如问题中所阐明的那样,希望避免拥有父行。 ADO.NET不允许这样做。如果您将c.Rows.Add(1, 1, null)
更改为c.Rows.Add(1, null, null)
,则不会再抛出InvalidConstraintException
。也就是说,它要求所有值都为null(而不是一个或多个),或者要存在于父表中的值。
我可能会考虑临时添加父行以保持约束检查,然后当您准备好插入数据库时,禁用约束检查并从父表中删除不必要的行。