Search code examples
c#sql-server-2008stored-proceduresstrongly-typed-dataset

How to find which column is violating Constraints?


I have a strongly typed data set which throws this error for null values,

System.Data.ConstraintException: Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints. at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.EndLoadData() at System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue) at System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords) at System.Data.Common.DbDataAdapter.FillInternal(DataSet dataset, DataTable[] datatables, Int32 startRecord, Int32 maxRecords, String srcTable, IDbCommand command, CommandBehavior behavior) at System.Data.Common.DbDataAdapter.Fill(DataTable[] dataTables, Int32 startRecord, Int32 maxRecords, IDbCommand command, CommandBehavior behavior) at System.Data.Common.DbDataAdapter.Fill(DataTable dataTable) at Fruits.DataAccess.FruitsTableAdapters.FruitsExtTableAdapter.GetFruits(String User, String Filter) at Fruits.DataAccess.FruitsDataAccess.GetFruits(String User, String Filter) at Fruits.WebServices.External.Fruity.GetFruits(String Filter)

All of the columns are populated with 1 single row I am testing it with,

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

Solution

  • You can use this method in your code. .NET checks the dataset thus to throw the exception.

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