Manejando XSD Dataset ConstraintExceptions
(1)
¿Alguien tiene algún consejo para lidiar con las Excepciones de Restricciones lanzadas por los conjuntos de datos XSD?
Esta es la excepción con el mensaje críptico:
System.Data.ConstraintException : Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
Un par de consejos que he encontrado últimamente.
Es mucho mejor utilizar los métodos TableAdapter FillByDataXXXX () en lugar de GetDataByXXXX () porque el DataTable pasado al método de llenado puede ser interrogado en busca de pistas:
- DataTable.GetErrors () devuelve una matriz de instancias de DataRow en error
- DataRow.RowError contiene una descripción del error de fila
- DataRow.GetColumnsInError () devuelve una matriz de instancias de DataColumn en error
Recientemente, envolví un código de interrogación en una subclase de ConstraintException que resultó ser un punto de partida útil para la depuración.
Uso del ejemplo 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);
}
Salida:
DetailedConstraintException: llenado de tabla fallido
Errores reportados para ConstraintExceptionHelper.DataSet + fooDataTable [foo]
Columnas por error: [1]
[ID_PRODUCTO]: filas totales afectadas: 1085
Errores de fila: [4]
[La columna ''PRODUCT_ID'' está limitada a ser única. El valor ''1'' ya está presente.] - total de filas afectadas: 1009
[La columna ''PRODUCT_ID'' está limitada a ser única. El valor ''2'' ya está presente.] - total de filas afectadas: 20
[La columna ''PRODUCT_ID'' está limitada a ser única. El valor ''4'' ya está presente.] - total de filas afectadas: 34
[La columna ''PRODUCT_ID'' está limitada a ser única. El valor ''6'' ya está presente.] - total de filas afectadas: 22
----> System.Data.ConstraintException: no se pudieron habilitar las restricciones. Una o más filas contienen valores que violan restricciones no nulas, únicas o de clave foránea.
No sé si esto es demasiado código para incluir en una respuesta de desbordamiento de pila, pero esta es la clase C # completa. Descargo de responsabilidad: esto funciona para mí, por favor siéntase libre de usar / modificar según corresponda.
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;
}
}