在Datatable上强制执行约束

4

在一个数据集中,有一个EnforceConstraints属性,指示是否启用约束条件。虽然DataTable也可以具有约束条件,但我无法禁用DataTable的约束条件。

我的情况是,我有一个DataTable,在其中使用一个列上的UniqueConstraint进行内存操作。有时我想临时禁用唯一约束条件。我该怎么做?我想到的唯一方法是删除并重新添加约束条件。有更好的方法吗?

6个回答

14

我的解决方案是这样的

using (IDataReader reader = ExecuteReader(sql))
            {
                DataTable dt = new DataTable();
                using (DataSet ds = new DataSet() { EnforceConstraints = false })
                {
                    ds.Tables.Add(dt);
                    dt.Load(reader, LoadOption.OverwriteChanges);
                    ds.Tables.Remove(dt);
                }
                return dt;
            }

这对我有用,只有使用mysql连接器才遇到过这个问题。翻阅了很多帖子,但只有这一个解决了它,因为我正在调用“SHOW PROCESSLIST”,所以无法控制输出。 - Liam Wheldon

9

DataTable没有公共的EnforceConstraints属性。我建议采用以下方法之一来禁用约束:

  • 如果想暂时禁用约束,可以使用DataTable.BeginLoadData()方法,再使用DataTable.EndLoadData()方法重新启用约束。
  • 将该DataTable添加到一个(虚拟的)DataSet中,并将属性DataSet.EnforceConstraints设置为false。

注意:禁用检查约束也会禁用检查与DataColumn.AllowDBNullDataColumn.MaxLength相关的值。


1
基本上我所做的是循环遍历约束并将其删除。执行操作后,再将约束重新添加到表中。

1

您可以使用约束来强制限制 DataTable 中的数据,以维护数据的完整性。当 DataSet 的 System.Data.DataSet.EnforceConstraints 属性为 true 时,会执行约束。

ADO.NET 中有两种约束:ForeignKeyConstraint 和 UniqueConstraint。默认情况下,当通过向 DataSet 添加 DataRelation 来创建两个或多个表之间的关系时,这两种约束都会自动创建。但是,您可以在创建关系时指定 createConstraints = false 来禁用此行为。


问题是关于暂时禁用约束条件的...虽然感谢解释。 - Gluip

0

这种异常通常发生在选择关键列(例如在JOIN操作中)时,结果表中有多个相同的值。比如你有一个客户表,其中CustID是主键,然后你将其与一个地址表进行连接,关系为1..n。客户可能有多个地址,最终得到的结果表中CustID会因为每个地址而重复出现。

数据表加载源模式并看到CustID是一个PK,因此它是唯一的,但是JOIN命令生成的结果表中CustID列却存在重复值,于是就会出现异常。

如果你想要处理和收集这个错误:

        using var tbl = new DataTable();
        using var reader = cmd.ExecuteReader();

        tbl.BeginLoadData();

        try
        {
            tbl.Load(reader);
        }
        catch (ConstraintException ex)
        {
            var sb = new StringBuilder();

            foreach (var row in tbl.GetErrors())
            {
                sb.AppendLine(row.RowError);

                foreach (var col in row.GetColumnsInError())
                {
                    var colError = col.ColumnName
                                   + ":" + row.GetColumnError(col);
                    sb.AppendLine(colError);
                }
            }

            reader.Close();
            tbl.Clear();
            tbl.Constraints.Clear();

            if (IgnoreErrors)
                tbl.Load(cmd.ExecuteReader());
            else
                throw new ConstraintException(sb.ToString(), ex);
        }
        finally
        {
            tbl.EndLoadData();
        }

"IgnoreErrors"是你的数据层或实体加载器等中的一个属性。如果想要避免错误,请使用"AS"将源列重命名为新名称:
"SELECT A.*, C.CustID AS CustIDNew FROM Addresses AS A INNER JOIN Customer AS C ON C.CustID = A.lCustID"

敬礼


-1

如果在加载datatable时存在数据,则可能会引发异常。为了安全起见,在加载之前请清除您的datatable,如下所示:

MyDataTable.Clear();
MyDataTable.Load(MyDataReader, LoadOption.OverwriteChanges);

这对我有用 :)


@Downvoter:您能否添加一条评论来解释您的投票理由?这对某些人可能会有所帮助。 - Stacked

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接