9

我有一個強類型數據集,其引發此錯誤空值,如何找到違反約束的列?

System.Data.ConstraintException:未能啓用約束。一個或多個行包含違反非空,唯一或外鍵約束的值。在System.Data.DataTable.EnableConstraints()處 System.Data.Common.DataAdapter.FillFromReader System.Data.DataTable.EndLoadData()(數據集的數據集,數據表 數據表,字符串srcTable要,DataReaderContainer的DataReader, 的Int32 startRecord, INT32最大記錄,的DataColumn parentChapterColumn, 對象parentChapterValue)在 System.Data.Common.DataAdapter.Fill(數據表[]數據表, IDataReader的DataReader的,INT32 startRecord,INT32最大記錄)在 System.Data.Common.DbDataAdapter.FillInternal(數據集數據集, DataTable [] datatables,Int32 startRecord,Int32 maxRecords,字符串 srcTable,IDbCommand命令,CommandBehavior行爲)在 System.Data.Com mon.DbDataAdapter.Fill(數據表[]數據表,的Int32 startRecord,的Int32最大記錄,IDbCommand的命令,的CommandBehavior 行爲)在System.Data.Common.DbDataAdapter.Fill(數據表 的dataTable)在 Fruits.DataAccess.FruitsTableAdapters.FruitsExtTableAdapter。 GetFruits(字符串 用戶,字符串濾波器)在 Fruits.DataAccess.FruitsDataAccess.GetFruits(字符串用戶,字符串 濾波器)在Fruits.WebServices.External.Fruity.GetFruits(字符串 濾波器)

所有的列用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 
+0

簡短回答:沒有 你可以用動態SQL做一些壞事,但我不會建議它。 – Tristan 2014-11-03 09:26:42

+0

謝謝@Tristan,我現在改變了我的問題 – Mathematics 2014-11-03 09:32:03

+0

嘗試'SELECT f。* FROM dbo.Fruits AS f WHERE NOT EXISTS(SELECT 1 FROM dbo.Categories AS c WHERE c.id = f.categoryID);'找到哪些行違反FK約束。 – 2014-11-03 09:51:23

回答

1

你可以在你的代碼中使用此方法。 .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); 
       } 
      } 
     }              
} 
+0

我沒有測試過這個,但我會接受它的努力,謝謝 – Mathematics 2014-11-14 15:14:30

1

問題在於其中一個列名稱在數據集中不匹配,不知道是什麼觸發了它,但匹配列的名稱和返回的列名解決了問題。

我還使用強類型數據集的「預覽數據」功能,幫助我找出問題所在。

13

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)); 
     } 
    } 
}