启用约束失败。一个或多个行包含违反非空、唯一或外键约束的值。

193

我执行了一个外连接,在informix数据库中成功执行了,但在我的代码中获得了以下异常:

DataTable dt = TeachingLoadDAL.GetCoursesWithEvalState(i, bat);

启用约束失败。一或多个行包含违反非空、唯一或外键约束的值。

我知道问题所在,但不知道如何修复它。

我在进行外部连接的第二个表中包含了一个由多个字段组成的主键,在之前的外部连接查询中这些字段是空值。

编辑:

    SELECT UNIQUE a.crs_e,  a.crs_e  || '/ ' || a.crst crs_name, b.period,
           b.crscls, c.crsday, c.from_lect, c.to_lect,
           c.to_lect - c.from_lect + 1 Subtraction, c.lect_kind, e.eval, e.batch_no,
           e.crsnum, e.lect_code, e.prof_course
    FROM rlm1course a, rfc14crsgrp b, ckj1table c, mnltablelectev d,
         OUTER(cc1assiscrseval e)  
    WHERE a.crsnum = b.crsnum 
    AND b.crsnum = c.crsnum 
    AND b.crscls = c.crscls 
    AND b.batch_no = c.batch_no 
    AND c.serial_key = d.serial_key  
    AND c.crsnum = e.crsnum  
    AND c.batch_no = e.batch_no  
    AND d.lect_code= e.lect_code 
    AND d.lect_code = .... 
    AND b.batch_no = ....
问题发生在表cc1assiscrseval上。 主键是(batch_no, crsnum, lect_code)。
如何解决这个问题? 编辑: 根据@PaulStock的建议: 我按他说的做,然后我得到:
?dt.GetErrors()[0]{System.Data.DataRow} HasErrors: true ItemArray: {object [10]} RowError:“列'eval'不允许DBNull.Value。”
因此,我通过将e.eval替换为NVL(e.eval,'') eval来解决我的问题,并解决了这个问题。 非常感谢。

当我从查询中删除 ,e.eval,e.batch_no,e.crsnum,e.lect_code,e.prof_course 时,一切都正常。请问问题出在哪里? - Anyname Donotcare
ADO.NET 中还存在一个错误,即“非唯一聚集索引”将在 DataTable 上创建一个错误的 Data.UniqueConstraint 项。 - Brain2000
27个回答

413

这个问题通常由以下原因之一引起:

  • 返回空值的列未设置为AllowDBNull
  • 具有相同主键的重复行会被返回。
  • 数据库和数据集之间的列定义不匹配(例如char字段的大小)

尝试本地运行查询并查看结果,如果结果集不太大。如果已经排除了空值,则我的猜测是主键列被重复使用。

或者,要查看确切的错误,您可以手动将Try/Catch块添加到生成的代码中,如下所示,然后在引发异常时打断:

enter image description here

然后在命令窗口中,对表调用GetErrors方法获取错误。
对于C#,命令将是? dataTable.GetErrors()
对于VB,命令是? dataTable.GetErrors

enter image description here

这将显示所有具有错误的数据行。您可以查看每个错误的RowError,其中应该说明无效的列以及问题所在。因此,要查看第一个出错数据行的错误,命令是:
? dataTable.GetErrors(0).RowError
或在C#中,它将是? dataTable.GetErrors()[0].RowError

enter image description here


4
非常感谢。 - Anyname Donotcare
5
太棒了。虽然那个方法没有起作用,但我可以在数据集上添加一个监视器,并在其后输入".GetErrors"并扩展它们的值。这非常有用。希望在下次需要它之前不会忘记它 :) - dwidel
6
是的,这确实很有帮助 - 我出错的原因是字段长度超过了表适配器中列的最大长度。我注意到的一件事是,为了在设计文件中触发断点,需要转到“工具”>“选项”>“调试”,并确保取消选中“仅调试我的代码”。然后就可以逐步执行设计文件的代码了。 - e-on
3
这非常有用,我发现数据列长度不匹配 - 数据库中增加了长度,但数据集没有跟进。 - Rob
1
仍然是一个相关的答案,仍然是一个很好的答案。非常感谢! - Minion91
显示剩余14条评论

46
你可以禁用数据集上的约束条件,这将有助于识别错误数据并解决问题。
例如:
dataset.TableA.Clear();
dataset.EnforceConstraints = false;
dataAdapter1.daTableA.Fill(dataset, TableA");

fill方法在你的情况下可能会有些不同。


1
这帮助我找到了导致问题的数据,它不是“坏数据”,而是数据源配置向导的错误行为。显然,它没有得到修订的列约束(而且我还错过了一个添加的表),尽管已经与数据库进行了交互...并且缓存未启用。 - fortboise
谢谢你的回答。我遇到了一个大小写敏感的问题,只需要在数据集中适当地设置即可解决。 - Dan
不幸的是,与DataSet不同,DataTable没有EnforceConstraints属性。为了解决这个问题,我只能创建一个仅用于此目的的DataSet,然后将DataTable添加到其中。非常感谢。 - Stringeater

13

这将查找表中所有存在错误的行,打印出该行的主键和发生在该行上的错误信息...

这是 C# 代码,但将其转换为 VB 不应该很难。

 foreach (DataRow dr in dataTable)
 {
   if (dr.HasErrors)
     {
        Debug.Write("Row ");
        foreach (DataColumn dc in dataTable.PKColumns)
          Debug.Write(dc.ColumnName + ": '" + dr.ItemArray[dc.Ordinal] + "', ");
        Debug.WriteLine(" has error: " + dr.RowError);
     }
  }

哎呀——抱歉,PKColumns是我在扩展DataTable时添加的一个内容,它告诉我构成DataTable主键的所有列。如果您知道DataTable中的主键列,可以在此处遍历这些列。在我的情况下,由于所有的datatables都知道它们的PK列,我可以为所有的表自动编写这些错误的调试代码。

输出的结果看起来像这样:

Row FIRST_NAME: 'HOMER', LAST_NAME: 'SIMPSON', MIDDLE_NAME: 'J',  has error: Column 'HAIR_COLOR' does not allow DBNull.Value.
如果您对上面的PKColumns部分感到困惑-它会打印列名和值,这不是必需的,但添加此信息有助于识别可能导致问题的列值,并进行故障排除。删除此部分并保留其余部分仍将打印生成的SQLite错误,其中将指出存在问题的列。

1
找出问题所在的绝妙方法。这确实帮助我解决了我继承的一个解决方案中存在数据不一致的问题。虽然它是在一个DataSet上,但我只是迭代每个表,然后迭代每行。如果可以的话,我会给它加10分。 - Andez
这对我有用。它是一个“列'MyColumn'不允许DBNull.Value”的错误,但其他方式都没有显示出来。谢谢 :) - Alex

7
  • 确保表适配器查询中的字段与您定义的查询中的字段匹配。数据访问层不喜欢不匹配的情况。这通常会在向表添加新字段后发生。

  • 如果您更改了数据库中varchar字段的长度,但XSS文件中包含的XML没有更新它,请在XML中找到字段名称和属性定义,并手动更改它。

  • 如果选择列表中的主键与返回的数据无关,则从表适配器中删除它们。

  • 在SQL Management Studio中运行查询,并确保没有返回重复记录。重复记录可能会生成重复的主键,导致此错误。

  • SQL联合查询可能会带来麻烦。我通过在其他记录之前添加“请选择员工”的记录来修改一个表适配器。对于其他字段,我提供了虚拟数据,包括长度为1的字符串。数据访问层从初始记录中推断出模式。随后的记录中,长度为12的字符串失败了。


1
欢迎来到 Stack Overflow,Bob。我已经编辑了你的回答(虽然还在审核中)。例如,我们不希望在回答中出现问候和签名(这被认为是“噪音”,请参阅常见问题解答)。无论如何,你的姓名和头像都会显示在回答下方。 - Christoffer Lette

5
这对我很有用,来源:这里 我遇到了这个错误,但它与数据库约束无关(至少在我的情况下)。我有一个.xsd文件,其中包含一个GetRecord查询,返回一组记录。该表的其中一列是“nvarchar(512)”,在项目中途我需要将其更改为“nvarchar(MAX)”。
一切都很好,直到用户在该字段上输入超过512个字符,我们开始收到著名的错误消息“无法启用约束。一行或多行包含违反非空、唯一或外键约束的值。”
解决方案:检查DataTable中所有列的MaxLength属性。
我将从“nvarchar(512)”更改为“nvarchar(MAX)”列仍然在MaxLength属性上保留了512个值,所以我将其更改为“-1”,它就可以工作了!!

我的问题也可能是MaxLength。我使用VWD 2010数据集设计器。源表被其他人更改了。我修改了SQL查询以选择,认为这将刷新所有列,但显然它没有更新现有长度。因此,我修改了查询以选择一个字段,保存了.xsd,在Notepad++中打开.xsd以检查除一个MaxLength def外的所有内容,然后再次修改了查询以选择。这刷新了MaxLengths并使我摆脱了这个错误。 - Mark Berry
非常感谢,我一整天都在苦思冥想,因为所有的报告都显示正常。我还不得不改成nvarchar(MAX),但是DataTable仍然保持着MaxLength为10!我欠你一杯饮料! - Jon D

5
问题出现在数据访问设计器中。在Visual Studio中,当我们将“服务器资源管理器”中的视图拉到设计器窗口时,它会随机地在某个列上添加一个主键或者将某些东西标记为NOT NULL,尽管它实际上被设置为空。尽管SQL数据库服务器中实际的视图创建没有定义任何主键或NOT NULL,但是VS设计器正在添加此关键字/约束。
您可以在设计器中看到这一点 - 它显示在列名左侧的关键字图标中。
解决方案:右键单击关键字图标,然后选择“删除关键字”。这应该解决问题。您还可以右键单击列并选择“属性”以查看VS数据访问设计器中列的属性列表,并相应地更改值。

3
我的问题在于,当我在 xsd 文件中的数据表上将 AllowDBNull 设置为 True 时,日期字段开始正常工作。

3
这个错误也在我的项目中出现过。我尝试了所有在此发帖中提出的解决方案,但是没有任何运气,因为问题与字段大小、表键字段定义、约束或强制执行约束数据集变量无关。
在我的情况下,我还有一个.xsd对象,我在项目设计时间将其放置在那里(数据访问层)。当您将数据库表对象拖入数据集可视项时,它会从底层数据库读取每个表定义,并将约束精确地复制到数据集对象中,就像在创建数据库中的表时定义它们一样(在我的情况下为SQL Server 2008 R2)。这意味着每个使用“非空”或“外键”的约束创建的表列也必须存在于您的SQL语句或存储过程的结果中。
在我将所有关键列和定义为“非空”的列包含在我的查询中后,问题完全消失了。

2

听起来可能是使用以下选定的一个或多个列:

   e.eval, e.batch_no, e.crsnum, e.lect_code, e.prof_course

在您的数据集定义中,AllowDBNull设置为False


我在这个表中为所有列设置了allow null = true,但没有成功。 - Anyname Donotcare

2
感谢您迄今为止所做出的所有贡献。我想要补充一点,即使一个人已经成功地将数据库规范化,更新了应用程序中的任何模式更改(例如数据集),还存在另一个原因:SQL笛卡尔积(在查询中连接表时)。
笛卡尔查询结果的存在会导致两个或多个表的主键(或关键字)表中出现重复记录。 即使在SQL中指定了“Where”子句,如果JOIN与次要表包含不相等的JOIN(从2个或多个不相关的表中获取数据时很有用),仍可能发生笛卡尔积:

FROM tbFirst INNER JOIN tbSystem ON tbFirst.reference_str <> tbSystem.systemKey_str

解决方法: 表应该是相关的。
谢谢。 chagbert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接