【问题标题】:How to find which column is violating Constraints?如何找到违反约束的列?
【发布时间】:2014-11-03 09:07:15
【问题描述】:

我有一个强类型数据集,它会为空值抛出此错误,

System.Data.ConstraintException:无法启用约束。一个或 更多行包含违反非空、唯一或外键的值 约束。在 System.Data.DataTable.EnableConstraints() 在 System.Data.DataTable.EndLoadData() 在 System.Data.Common.DataAdapter.FillFromReader(数据集数据集, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, 对象 parentChapterValue) 在 System.Data.Common.DataAdapter.Fill(DataTable[] 数据表, IDataReader dataReader, Int32 startRecord, Int32 maxRecords) 在 System.Data.Common.DbDataAdapter.FillInternal(数据集数据集, DataTable[] 数据表,Int32 startRecord,Int32 maxRecords,字符串 srcTable、IDbCommand 命令、CommandBehavior 行为)在 System.Data.Common.DbDataAdapter.Fill(DataTable[] 数据表,Int32 startRecord、Int32 maxRecords、IDbCommand 命令、CommandBehavior 行为)在 System.Data.Common.DbDataAdapter.Fill(DataTable 数据表)在 Fruits.DataAccess.FruitsTableAdapters.FruitsExtTableAdapter.GetFruits(字符串 用户,字符串过滤器)在 Fruits.DataAccess.FruitsDataAccess.GetFruits(字符串用户,字符串 过滤器)在 Fruits.WebServices.External.Fruity.GetFruits(String 过滤器)

所有的列都填充了 1 行我正在测试它,

USE [FruitDataBase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Fruits](
    [ID] [int] NOT NULL,
    [CategoryID] [int] NOT NULL,
    [Title] [nvarchar](255) NOT NULL,
    [URL] [nvarchar](255) NOT NULL,
    [Status] [nvarchar](70) NOT NULL,
    [Description] [nvarchar](1024) NULL,
    [User1] [nvarchar](50) NOT NULL,
    [Date] [datetime] NOT NULL,
    [User2] [nvarchar](50) NULL,
    [Date2] [datetime] NULL,
    [Impact] [nvarchar](255) NULL,
    [Solution] [nvarchar](1024) NULL,
 CONSTRAINT [PK_Fruits] PRIMARY KEY CLUSTERED 
(
    [ID] 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].[Fruits]  WITH CHECK ADD  CONSTRAINT [FK_Fruits_Categories] FOREIGN KEY([CategoryID])
REFERENCES [dbo].[Categories] ([ID])
GO

ALTER TABLE [dbo].[Fruits] CHECK CONSTRAINT [FK_Fruits_Categories]
GO

【问题讨论】:

  • 简短回答:不,你可以用动态 sql 做一些讨厌的事情,但我不建议这样做。
  • 谢谢@Tristan,我现在改变了我的问题
  • 尝试SELECT f.* FROM dbo.Fruits AS f WHERE NOT EXISTS (SELECT 1 FROM dbo.Categories AS c WHERE c.id = f.categoryID); 找出哪些行违反了 FK 约束。

标签: c# sql-server-2008 stored-procedures strongly-typed-dataset


【解决方案1】:

DataSet / DataTable 具有获取有关错误的更多详细信息的属性。

所以这些细节并不像你想象的那样在异常本身中,这就是诀窍。见http://www.codeproject.com/Tips/405938/Debugging-DataSet-Constraint-Errors

示例:

catch (ConstraintException)
{
    DataRow[] rowErrors = this.YourDataSet.YourDataTable.GetErrors();

    System.Diagnostics.Debug.WriteLine("YourDataTable Errors:" 
        + rowErrors.Length);

    for (int i = 0; i < rowErrors.Length; i++)
    {
        System.Diagnostics.Debug.WriteLine(rowErrors[i].RowError);

        foreach (DataColumn col in rowErrors[i].GetColumnsInError())
        {
            System.Diagnostics.Debug.WriteLine(col.ColumnName 
                + ":" + rowErrors[i].GetColumnError(col));
        }
    }
}

【讨论】:

  • 遗留项目中的救生员。谢谢!
  • 如果使用 Visual Studio 调试并停止异常,您可以在立即窗口中输入:yourDataset.yourTable.GetErrors()[0].RowError,您将看到第一个约束错误
【解决方案2】:

您可以在代码中使用此方法。 .NET 检查数据集从而引发异常。

       public void CheckDataSet(DataSet dataSet)
       {                                                              
        Assembly assembly = Assembly.LoadFrom(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Data.dll");
        Type type = assembly.GetType("System.Data.ConstraintEnumerator");
        ConstructorInfo ctor = type.GetConstructor(new[] { typeof(DataSet) });
        object instance = ctor.Invoke(new object[] { dataSet });                
        BindingFlags bf = BindingFlags.Instance | BindingFlags.Public;
        MethodInfo m_GetNext = type.GetMethod("GetNext", bf);

        while ((bool)m_GetNext.Invoke(instance, null))
        {
            bool flag = false;
            MethodInfo m_GetConstraint = type.GetMethod("GetConstraint", bf);                    
            Constraint constraint = (Constraint) m_GetConstraint.Invoke(instance, null);
            Type constraintType = constraint.GetType();
            BindingFlags bfInternal = BindingFlags.Instance | BindingFlags.NonPublic;
            MethodInfo m_IsConstraintViolated = constraintType.GetMethod("IsConstraintViolated", bfInternal);                    
            flag = (bool)m_IsConstraintViolated.Invoke(constraint, null);
            if (flag)                    
                Debug.WriteLine("Constraint violated, ConstraintName: " + constraint.ConstraintName + ", tableName: " + constraint.Table);                                            
        }

        foreach (DataTable table in dataSet.Tables)
        {
            foreach (DataColumn column in table.Columns)
            {
                Type columnType = column.GetType();
                BindingFlags bfInternal = BindingFlags.Instance | BindingFlags.NonPublic;

                bool flag = false;
                if (!column.AllowDBNull)
                {                            
                    MethodInfo m_IsNotAllowDBNullViolated = columnType.GetMethod("IsNotAllowDBNullViolated", bfInternal);                                                        
                    flag = (bool)m_IsNotAllowDBNullViolated.Invoke(column, null);
                    if (flag)
                    {
                        Debug.WriteLine("DBnull violated  --> ColumnName: " + column.ColumnName + ", tableName: " + column.Table.TableName);
                    }
                }
                if (column.MaxLength >= 0)
                {
                    MethodInfo m_IsMaxLengthViolated = columnType.GetMethod("IsMaxLengthViolated", bfInternal);                            
                    flag = (bool)m_IsMaxLengthViolated.Invoke(column, null);                            
                    if (flag)                            
                        Debug.WriteLine("MaxLength violated --> ColumnName: " + column.ColumnName + ", tableName: " + column.Table.TableName);
                }
            }
        }                                                    
}

【讨论】:

  • 我没有对此进行测试,但我会接受它的努力,谢谢
【解决方案3】:

问题在于数据集中的列名之一不匹配,不确定是什么触发了它,但将列名与返回的列名匹配解决了问题。

我还使用了强类型数据集的“预览数据”功能,帮助我找出问题所在。

【讨论】:

    【解决方案4】:

    以防万一有人(目前像我一样)使用 VB.NET 中的旧项目使用 DataSets 为你们节省一分钟,我将在 @AFract 答案中发布一个 VB.NET 版本。希望它适合这里:

            Catch ex As ConstraintException
                Dim rowErrors = this.YourDataSet.YourDataTable.GetErrors()
                System.Diagnostics.Debug.WriteLine("YourDataTable Errors:" & rowErrors.Length)
                For i = 0 To rowErrors.Length - 1
                    For Each col As DataColumn In rowErrors(i).GetColumnsInError()
                        System.Diagnostics.Debug.WriteLine(col.ColumnName & ":" & rowErrors(i).GetColumnError(col))
                    Next
                Next
            End Try
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-02
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 2018-12-31
      • 2020-04-01
      • 1970-01-01
      相关资源
      最近更新 更多