关于c#:MySqlDataReader:DataTable.Fill(reader)抛出ConstraintException

MySqlDataReader: DataTable.Fill(reader) throws ConstraintException

我有两个表ordersorderdetails

表订单(PK = id,orderno上的UNIQUE索引)

1
2
3
|id|orderno|
| 1|1000   |
| 2|1001   |

表顺序详细信息(PK = ID)

1
2
3
|id|orderid|item|qty|
| 1|      1|ABC |  3|
| 2|      1|XYZ |  4|

现在我想用以下查询数据:

1
2
SELECT o.orderno, od.item, od.qty
  FROM orders o

内部联接订单详细信息od ON o.orderno = od.order

返回:

1
2
3
|orderno|item|qty|
|1000   |ABC |  3|
|1000   |XYZ |  4|

但是,如果我使用以下代码将结果加载到DataTable中,它将失败:

1
2
3
4
5
6
7
8
var connectionString ="Server=localhost;Database=orders;Uid=root;";
var commandText ="SELECT o.orderno, od.item, od.qty" + Environment.NewLine +
                 "FROM orders o" + Environment.NewLine +
                 "INNER JOIN orderdetails od ON o.orderno = od.order";

var reader = MySqlHelper.ExecuteReader(connectionString, commandText);
var table = new DataTable("OrdersQuery");
table.Fill(reader); // throws ConstraintException

问题是

1
table.Constraints[0]

是orderno列上的UniqueConstraints。 可能是因为

1
reader.GetSchemaTable()

对orderno有一个IsUnique=true条目(在基表中为true,但对联接查询而言为true)。

更糟糕的是,这也无济于事:

1
2
3
table.BeginLoadData(); // msdn docs claim that this should disable constraints
table.Load(reader);
table.EndLoadData();

任何想法如何解决这一问题?

堆栈跟踪:

1
2
3
4
5
6
7
8
9
10
11
12
System.Data.ConstraintException Was Unhandled.
  Message=Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
  Source=System.Data
  StackTrace:
       bei System.Data.DataTable.EnableConstraints()
       bei System.Data.DataTable.set_EnforceConstraints(Boolean value)
       bei System.Data.DataTable.EndLoadData()
       bei System.Data.Common.DataAdapter.FillFromReader(DataSet dataset, DataTable datatable, String srcTable, DataReaderContainer dataReader, Int32 startRecord, Int32 maxRecords, DataColumn parentChapterColumn, Object parentChapterValue)
       bei System.Data.Common.DataAdapter.Fill(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
       bei System.Data.Common.LoadAdapter.FillFromReader(DataTable[] dataTables, IDataReader dataReader, Int32 startRecord, Int32 maxRecords)
       bei System.Data.DataTable.Load(IDataReader reader, LoadOption loadOption, FillErrorEventHandler errorHandler)
       bei System.Data.DataTable.Load(IDataReader reader)

我遇到了同样的问题,但是通过使用以下文章中的解决方法进行了修复:http://bugs.mysql.com/bug.php?id=65065(底部):

1
2
3
4
5
6
7
8
cmd.CommandText ="SELECT cam.no_serie, t.mnt FROM trx t LEFT JOIN camn cam USING(id_camn)";
    MySqlDataReader dr = cmd.ExecuteReader();
    DataSet ds = new DataSet();
    DataTable dataTable = new DataTable();
    ds.Tables.Add(dataTable);
    ds.EnforceConstraints = false;
    dataTable.Load(dr);
    dr.Close();

我才知道

1
table.Fill(reader)

如果我已经添加了列,则不会创建约束。

因此,我使用了一个不错的扩展方法来解决此问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    public static void Load(this DataTable table, IDataReader reader, bool createColumns)
    {

        if (createColumns)
        {
            table.Columns.Clear();
            var schemaTable = reader.GetSchemaTable();
            foreach (DataRowView row in schemaTable.DefaultView)
            {
                var columnName = (string)row["ColumnName"];
                var type = (Type)row["DataType"];
                table.Columns.Add(columnName, type);
            }
        }

        table.Load(reader);
    }

用法:

1
table.Fill(reader, true);


今天我遇到了同样的错误,想分享。我的问题是一个LONGTEXT类型的列。如果我在查询中包含LONGTEXT列并尝试加载数据集而不指定列名,则会引发异常。根据SchlaWiener的代码,我将代码重写如下,现在一切都很好。

1
2
3
4
5
6
7
MySqlDataReader resultSet = cmd.ExecuteReader();
dt.Columns.Clear();
for (int i = 0; i < resultSet.FieldCount; i++)
{
    dt.Columns.Add(resultSet.GetName(i));
}
dt.Load(resultSet);

有一个简单的肮脏方法如何解决它-使用concat函数在具有唯一约束的查询中包围列:

1
var commandText ="SELECT CONCAT(o.orderno, ''), od.item, od.qty ...";

我在查询中遇到了类似的问题,当使用MYSQL Reader加载Datatable()时,它会生成错误NON-NULL,UNIQUE或FOREIGN-KEY。

最后,我通过更改MySQL Connector.NET版本解决了它。

https://dev.mysql.com/downloads/connector/net/


MySQL在唯一索引中允许多个空值。这将导致ConstraintException填充。解决方法:在" table.Constraints"列表中找到此约束,然后将其删除或清除所有约束。