【问题标题】:MySqlDataReader: DataTable.Fill(reader) throws ConstraintExceptionMySqlDataReader:DataTable.Fill(reader) 抛出 ConstraintException
【发布时间】:2011-11-26 17:05:46
【问题描述】:

我有两张桌子ordersorderdetails

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

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

table orderdetails (PK = id)

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

现在我想查询数据:

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

INNER JOIN orderdetails od ON o.orderno = od.order

返回:

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

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

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

问题是,

table.Constraints[0]

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

reader.GetSchemaTable() 

对于 orderno 有一个 IsUnique=true 条目(在基表中为 true,但在连接查询中不为 true)。

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

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

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

堆栈跟踪:

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)

【问题讨论】:

    标签: c# mysql datareader mysql-connector mysqldatareader


    【解决方案1】:

    我遇到了同样的问题,但通过使用这篇文章中的解决方法解决了它:http://bugs.mysql.com/bug.php?id=65065(底部):

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

    【讨论】:

      【解决方案2】:

      我才发现

      table.Fill(reader)
      

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

      所以我通过使用一个不错的小扩展方法解决了这个问题:

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

      用法:

      table.Fill(reader, true);
      

      【讨论】:

      • 感谢朋友的分享!像魅力一样工作。
      【解决方案3】:

      有一种简单的脏方法可以解决它 - 在查询中用 concat 函数的唯一约束包围列:

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

      【讨论】:

        【解决方案4】:

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

        MySqlDataReader resultSet = cmd.ExecuteReader();
        dt.Columns.Clear();
        for (int i = 0; i < resultSet.FieldCount; i++)
        {
            dt.Columns.Add(resultSet.GetName(i));
        }
        dt.Load(resultSet);
        

        【讨论】:

          【解决方案5】:

          MySQL 允许在唯一索引中有多个空值。这会导致填充时出现 ConstraintException。如何修复:在 'table.Constraints' 列表中找到此约束并将其删除或仅清除所有约束。

          【讨论】:

          • 多个空值不是问题。 table.Load() 方法在 Orderno 上创建了一个 Contraint,因为 reader.GetSchemaTable() 对于 Orderno 列有 IsUnique = true,这对于 Join 查询是错误的。
          • 我也想过这个问题。但是,如果我使用接受 FillError 委托的重载,它不会触发。不知道为什么,因为这是我应该期待的。
          【解决方案6】:

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

          最后我通过更改 MySQL Connector.NET 版本解决了这个问题。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2013-04-29
            • 2014-10-31
            • 1970-01-01
            • 1970-01-01
            • 2013-01-20
            • 2021-10-08
            • 1970-01-01
            相关资源
            最近更新 更多