Pergunta

Alguém tem alguma dica para lidar com ConstraintExceptions lançadas por conjuntos de dados XSD?

Esta é a exceção com a mensagem enigmática:

System.Data.ConstraintException : Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
Foi útil?

Solução

Algumas dicas que descobri recentemente.

  1. É muito melhor usar os métodos TableAdapter FillByDataXXXX() em vez dos métodos GetDataByXXXX() porque o DataTable passado para o método fill pode ser interrogado em busca de pistas:

    • DataTable.GetErrors() retorna um matriz de instâncias DataRow em erro
    • DataRow.RowError contém um Descrição do erro de linha
    • DataRow.GetColumnsInError() retorna uma matriz de instâncias DataColumn em erro
  2. Recentemente, juntei alguns códigos de interrogação em uma subclasse de ConstraintException que acabou sendo um ponto de partida útil para depuração.

Exemplo de uso de C#:

Example.DataSet.fooDataTable table = new DataSet.fooDataTable();

try
{
    tableAdapter.Fill(table);
}
catch (ConstraintException ex)
{
    // pass the DataTable to DetailedConstraintException to get a more detailed Message property
    throw new DetailedConstraintException("error filling table", table, ex);
}

Saída:

DetalhadoConstraintException:falha no preenchimento da tabela
Erros relatados para ConstraintExceptionHelper.DataSet+fooDataTable [foo]
Colunas com erro:[1]
[PRODUCT_ID] – total de linhas afetadas:1085
Erros de linha:[4]
[A coluna 'PRODUCT_ID' é restrita para ser exclusiva.O valor '1' já está presente.] - total de linhas afetadas:1009
[A coluna 'PRODUCT_ID' é restrita para ser exclusiva.O valor '2' já está presente.] - total de linhas afetadas:20
[A coluna 'PRODUCT_ID' é restrita para ser exclusiva.O valor '4' já está presente.] - total de linhas afetadas:34
[A coluna 'PRODUCT_ID' é restrita para ser exclusiva.O valor '6' já está presente.] - total de linhas afetadas:22
----> System.Data.ConstraintException:Falha ao ativar restrições.Uma ou mais linhas contêm valores que violam restrições não nulas, exclusivas ou de chave estrangeira.

Não sei se isso é muito código para incluir em uma resposta do Stack Overflow, mas aqui está a classe C# completa.Isenção de responsabilidade:isso funciona para mim, sinta-se à vontade para usar/modificar conforme apropriado.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace ConstraintExceptionHelper
{

    /// <summary>
    /// Subclass of ConstraintException that explains row and column errors in the Message property
    /// </summary>
    public class DetailedConstraintException : ConstraintException
    {

        private const int InitialCountValue = 1;


        /// <summary>
        /// Initialises a new instance of DetailedConstraintException with the specified string and DataTable
        /// </summary>
        /// <param name="message">exception message</param>
        /// <param name="ErroredTable">DataTable in error</param>
        public DetailedConstraintException(string message, DataTable erroredTable)
            : base(message)
        {
            ErroredTable = erroredTable;
        }


        /// <summary>
        /// Initialises a new instance of DetailedConstraintException with the specified string, DataTable and inner Exception
        /// </summary>
        /// <param name="message">exception message</param>
        /// <param name="ErroredTable">DataTable in error</param>
        /// <param name="inner">the original exception</param>
        public DetailedConstraintException(string message, DataTable erroredTable, Exception inner)
            : base(message, inner)
        {
            ErroredTable = erroredTable;
        }


        private string buildErrorSummaryMessage()
        {
            if (null == ErroredTable) { return "No errored DataTable specified"; }
            if (!ErroredTable.HasErrors) { return "No Row Errors reported in DataTable=[" + ErroredTable.TableName + "]"; }

            foreach (DataRow row in ErroredTable.GetErrors())
            {
                recordColumnsInError(row);
                recordRowsInError(row);
            }

            StringBuilder sb = new StringBuilder();

            appendSummaryIntro(sb);
            appendErroredColumns(sb);
            appendRowErrors(sb);

            return sb.ToString();
        }


        private void recordColumnsInError(DataRow row)
        {
            foreach (DataColumn column in row.GetColumnsInError())
            {
                if (_erroredColumns.ContainsKey(column.ColumnName))
                {
                    _erroredColumns[column.ColumnName]++;
                    continue;
                }

                _erroredColumns.Add(column.ColumnName, InitialCountValue);
            }
        }


        private void recordRowsInError(DataRow row)
        {
            if (_rowErrors.ContainsKey(row.RowError))
            {
                _rowErrors[row.RowError]++;
                return;
            }

            _rowErrors.Add(row.RowError, InitialCountValue);
        }


        private void appendSummaryIntro(StringBuilder sb)
        {
            sb.AppendFormat("Errors reported for {1} [{2}]{0}", Environment.NewLine, ErroredTable.GetType().FullName, ErroredTable.TableName);
        }


        private void appendErroredColumns(StringBuilder sb)
        {
            sb.AppendFormat("Columns in error: [{1}]{0}", Environment.NewLine, _erroredColumns.Count);

            foreach (string columnName in _erroredColumns.Keys)
            {
                sb.AppendFormat("\t[{1}] - rows affected: {2}{0}",
                                Environment.NewLine,
                                columnName,
                                _erroredColumns[columnName]);
            }
        }


        private void appendRowErrors(StringBuilder sb)
        {
            sb.AppendFormat("Row errors: [{1}]{0}", Environment.NewLine, _rowErrors.Count);

            foreach (string rowError in _rowErrors.Keys)
            {
                sb.AppendFormat("\t[{1}] - rows affected: {2}{0}",
                                Environment.NewLine,
                                rowError,
                                _rowErrors[rowError]);
            }
        }


        /// <summary>
        /// Get the DataTable in error
        /// </summary>
        public DataTable ErroredTable
        {
            get { return _erroredTable; }
            private set { _erroredTable = value; }
        }


        /// <summary>
        /// Get the original ConstraintException message with extra error information
        /// </summary>
        public override string Message
        {
            get { return base.Message + Environment.NewLine + buildErrorSummaryMessage(); }
        }


        private readonly SortedDictionary<string, int> _rowErrors = new SortedDictionary<string, int>();
        private readonly SortedDictionary<string, int> _erroredColumns = new SortedDictionary<string, int>();
        private DataTable _erroredTable;
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top