SQL Server 2000的神秘约束问题

时间:2009-11-06 08:56:06

标签: web-applications sql-server-2000 constraints strongly-typed-dataset

我在VS 2003中编写的VB .NET Web应用程序中,在框架1.1上收到以下错误。 Web应用程序在Windows Server 2000,IIS 5上运行,并且正在从在同一台计算机上运行的SQL Server 2000数据库中读取。

  

System.Data.ConstraintException:   无法启用约束。一个或   更多行包含违反的值   非null,唯一或外键   限制。在   System.Data.DataSet.FailedEnableConstraints()   在   System.Data.DataSet.EnableConstraints()   在   System.Data.DataSet.set_EnforceConstraints(布尔   价值)   System.Data.DataTable.EndLoadData()
  在   System.Data.Common.DbDataAdapter.FillFromReader(对象   data,String srcTable,IDataReader   dataReader,Int32 startRecord,Int32   maxRecords,DataColumn   parentChapterColumn,Object   parentChapterValue)at   System.Data.Common.DbDataAdapter.Fill(数据集   dataSet,String srcTable,IDataReader   dataReader,Int32 startRecord,Int32   maxRecords)at   System.Data.Common.DbDataAdapter.FillFromCommand(对象   data,Int32 startRecord,Int32   maxRecords,String srcTable,   IDbCommand命令,CommandBehavior   行为)   System.Data.Common.DbDataAdapter.Fill(数据集   dataSet,Int32 startRecord,Int32   maxRecords,String srcTable,   IDbCommand命令,CommandBehavior   行为)   System.Data.Common.DbDataAdapter.Fill(数据集   数据集)

当网络应用程序处于高负载时,会出现此问题。当卷不足时系统运行正常,但是当请求数变高时,系统开始使用上述异常消息拒绝传入的请求。一旦问题出现,很少有请求实际通过并正常处理,每30个中大约2个。绝大多数请求失败,直到执行SQL Server重启或IIS重置。系统然后开始正常处理请求,并在一段时间后开始抛出相同的错误。

当数据适配器针对SELECT语句运行Fill()方法时,会发生错误,以填充强类型数据集。看来数据集不喜欢它给出的数据并抛出此异常。在各种SELECT语句上发生此错误,作用于不同的表。

我重新生成了数据集并检查了相关的约束,以及从中读取数据的表。数据集定义和表中的数据都很好。

不可否认,考虑到当前收到的传入请求数量,运行 Web应用程序和SQL Server 2000的硬件严重过时。 SQL Server消耗的RAM量是动态分配的,在高峰时间,SQL Server在服务器上的总共3.5 GB中最多可以消耗2.8 GB。

起初我怀疑某种索引或数据库损坏,但在运行DBCC CHECKDB之后,数据库中没有发现错误。所以现在我想知道这个错误是否是系统硬件限制的结果。 SQL Server是否有可能以某种方式搞乱它应该传递给数据集的数据,从而导致由于数据类型/长度不匹配导致的约束违规?

我尝试访问检索到的数据集表中的数据行的RowError消息,但我一直得到空字符串。我知道有问题的数据表的HasErrors = true。我没有设置EnableConstraints = false,我不想这样做。

提前致谢。

1 个答案:

答案 0 :(得分:0)

问题是缺少有用的诊断错误消息。我编写了一个类,其中包含告诉您约束问题的方法,而不仅仅是给您一个无用的通用错误消息。您可以按以下方式使用这些方法。

Dim ds As New dsMyDataset

'Turn off constraints during the data load'
DatasetAnalyzer.DatasetAnalyzer_Init(ds)

'Ready to fill one or more tables'
Dim da1 As New dsMyDatasetTableAdapters.Table1TableAdapter
da1.Fill(ds.Table1)

'Checks relationships and constraints before turning them back on.'
DatasetAnalyzer.DatasetAnalyzer_AnalyzeAndConfirm(ds)

'Ready to use your dataset now'
Return ds

这是完整的课程。

Public Class DatasetAnalyzer

#Region " DatasetAnalyzer "

    'Run this before loading tables in your dataset, if you plan to call DatasetAnalyzer_GetMissingParentRows.
    'Must call DatasetAnalyzer_AnalyzeAndConfirm when done creating dataset to re-enable relations.
#Region " DatasetAnalyzer_Init "
    Public Shared Sub DatasetAnalyzer_Init(ByVal ds As Data.DataSet)
        ds.EnforceConstraints = False

        ds.BeginInit()
        For Each dt As Data.DataTable In ds.Tables
            dt.BeginInit()
            dt.BeginLoadData()

        Next

    End Sub
#End Region

    'Checks for dataset constraint errors and gives detailed error messages if any are found.
    'Assumes DatasetAnalyzer_Init is called on that dataset
#Region " DatasetAnalyzer_AnalyzeAndConfirm "
    Public Shared Sub DatasetAnalyzer_AnalyzeAndConfirm(ByVal ds As Data.DataSet)
        DatasetAnalyzer_EnsureInitialization(ds)

        Try
            For Each dt As Data.DataTable In ds.Tables
                dt.EndLoadData()
                dt.EndInit()
            Next
            ds.EndInit()

            ds.EnforceConstraints = True

        Catch ex As Data.ConstraintException
            'We've found a constraint exception...figure out what it is

            Dim sErrorMessage As String = "DatasetAnalyzer_AnalyzeAndConfirm : "

            For Each oTbl As Data.DataTable In ds.Tables
                If oTbl.HasErrors Then

                    'Report the first error only
                    Dim oRow As Data.DataRow = oTbl.GetErrors(0)
                    sErrorMessage &= oTbl.TableName & " : " & oRow.RowError & " : "

                    'Detail for Foreign Key Violations
                    If oTbl.ParentRelations IsNot Nothing Then
                        For Each oRel As Data.DataRelation In oTbl.ParentRelations
                            If oRel.ChildKeyConstraint IsNot Nothing AndAlso oRow.GetParentRow(oRel) Is Nothing Then
                                'a parent constraint for this relation exists and the data that is constrained is non-existant.  If this isn't a null value then we found a problem
                                For Each o As Data.DataColumn In oRel.ChildColumns
                                    If Not oRow.IsNull(o) Then
                                        'We have a confirmed foreign key violation...generate a pretty message

                                        Dim ParentColumnNames(oRel.ParentColumns.Length - 1) As String
                                        Dim ChildColumnNames(oRel.ChildColumns.Length - 1) As String


                                        For i As Int32 = 0 To ParentColumnNames.Length - 1
                                            ParentColumnNames(i) = oRel.ParentColumns(i).ColumnName
                                        Next

                                        For i As Int32 = 0 To ChildColumnNames.Length - 1
                                            ChildColumnNames(i) = oRel.ChildColumns(i).ColumnName
                                        Next

                                        sErrorMessage &= "ParentTable = " & oRel.ParentTable.TableName & " (" & String.Join(", ", ParentColumnNames) & "), "
                                        sErrorMessage &= "ChildTable = " & oRel.ChildTable.TableName & " (" & String.Join(", ", ChildColumnNames) & "), "

                                    End If
                                Next
                            End If
                        Next
                    End If


                    'Additional Column info that might be usefull
                    If oRow.RowError.Contains("MaxLength") Then
                        For Each oCol As Data.DataColumn In oRow.GetColumnsInError
                            sErrorMessage &= oCol.ColumnName & ".MaxLength = " & oCol.MaxLength
                        Next
                    End If


                    'Report the error with details about the row that errored
                    sErrorMessage &= Environment.NewLine & Environment.NewLine & "Debug Data = " & DatasetAnalyzer_GetRowDebugData(oRow)
                    Throw New Exception(sErrorMessage)

                End If
            Next


            Throw New Exception("Dear Developer, Unknown Constraint Exeption", ex)
        End Try

    End Sub
#End Region

    'Returns an array of detached rows that are "missing" in the ParentTable.
    'Returns an empty array if no values exist
#Region " DatasetAnalyzer_GetMissingParentRows "
    Public Shared Function DatasetAnalyzer_GetMissingParentRows(ByVal ParentTable As Data.DataTable) As Data.DataRow()
        If ParentTable.DataSet Is Nothing Then
            Throw New Exception("Dear Developer, DatasetAnalyzer_GetMissingParentRows : ParentTable must belong to a dataset.  Table = " & ParentTable.TableName)
        End If

        DatasetAnalyzer_EnsureInitialization(ParentTable.DataSet)

        Dim drMissingParents As New Collections.Generic.List(Of Data.DataRow)

        Try
            'Turn on the constraints to see if anything breaks
            ParentTable.DataSet.EnforceConstraints = True

        Catch ex As Data.ConstraintException

            For Each oRel As Data.DataRelation In ParentTable.ChildRelations
                If oRel.ChildKeyConstraint IsNot Nothing AndAlso oRel.ChildTable.HasErrors Then
                    'This relationship has a child key constraint...this child table has errors

                    For Each oRow As Data.DataRow In oRel.ChildTable.GetErrors
                        If oRow.GetParentRow(oRel) Is Nothing Then
                            ' This foreign key that is constrained is non-existant.  If this isn't a null value then we found a problem
                            For Each o As Data.DataColumn In oRel.ChildColumns
                                If Not oRow.IsNull(o) Then
                                    ' non-null missing foreign key constraint
                                    Dim drMissingParent As Data.DataRow = ParentTable.NewRow

                                    ' Create the proposed parent record by matching the child record
                                    For i As Int32 = 0 To oRel.ParentColumns.Length - 1
                                        drMissingParent(oRel.ParentColumns(i)) = oRow(oRel.ChildColumns(i))
                                    Next

                                    'Search for a duplicate Missing Parent...only need to report each one once
                                    Dim bFoundDupe As Boolean = False
                                    For Each dr As Data.DataRow In drMissingParents
                                        bFoundDupe = True

                                        For i As Int32 = 0 To ParentTable.Columns.Count - 1
                                            If Not dr(i).Equals(drMissingParent(i)) Then
                                                bFoundDupe = False
                                                Exit For
                                            End If
                                        Next

                                        If bFoundDupe Then Exit For
                                    Next

                                    If Not bFoundDupe Then
                                        drMissingParents.Add(drMissingParent)
                                    End If

                                    Exit For 'Checking for non-nulls Columns
                                End If
                            Next
                        End If
                    Next
                End If
            Next
        End Try

        ParentTable.DataSet.EnforceConstraints = False

        Return drMissingParents.ToArray
    End Function
#End Region

    'Returns the string representation of row data
#Region " DatasetAnalyzer Private Support Methods "

    Private Shared Function DatasetAnalyzer_GetRowDebugData(ByVal oRow As Data.DataRow) As String
        Dim Values(oRow.Table.Columns.Count - 1) As String


        For Each oCol As Data.DataColumn In oRow.Table.Columns
            Dim Value As String
            If oRow.IsNull(oCol) Then
                Value = "<NULL>"
            Else
                Value = oRow(oCol).ToString
            End If

            Values(oCol.Ordinal) = oCol.ColumnName & ":" & Value
        Next


        Return String.Join(", ", Values)
    End Function

    Private Shared Sub DatasetAnalyzer_EnsureInitialization(ByVal ds As Data.DataSet)
        If ds Is Nothing Then
            Throw New Exception("Dear Developer, Must construct the ds object before calling InDatasetAnalyzer_Init (ds = New ...)")
        End If

        If ds.EnforceConstraints Then
            Throw New Exception("Dear Developer, call DatasetAnalyzer_Init before calling DatasetAnalyzer_AnalyzeAndConfirm")
        End If
    End Sub
#End Region
#End Region

End Class

现在您应该能够使用有用的信息进行故障排除。