加载 DataTable 时使用默认列值以避免 Null

Posted

技术标签:

【中文标题】加载 DataTable 时使用默认列值以避免 Null【英文标题】:Use default column values when loading DataTable to avoid Nulls 【发布时间】:2013-07-10 20:11:36 【问题描述】:

我有一个 xsd 数据集架构,它允许我为 DataTable 定义一个结构。对于每一列,我都设置了一个默认值,因此在构造新行时,我得到实例化值(“”代表字符串,0 代表整数)而不是 DbNull

我想在以下两个方法调用中使用DataTable.LoadSqlDataAdapter.Fill 时保留它

Dim table1 As New CodeSetSchemas.EntityByRoleDataTable()
Using reader As SqlDataReader = cmd.ExecuteReader()
    table1.Load(reader)
End Using

Dim table2 As New CodeSetSchemas.EntityByRoleDataTable()
Using adapter As New SqlDataAdapter(cmd)
    adapter.Fill(table2)
End Using

但是当这些方法中的任何一个创建新行时,它们实际上会将数据库中的 DbNull 写入该行。如果我将每列上的AllowDBNull 属性设置为False,则会出现以下异常:

Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.

有没有办法在填充 DataTable 时保留每行的默认值?

【问题讨论】:

【参考方案1】:

我也遇到了这个问题。不幸的是,DataTable.Load 或 SqlDataAdapter.Fill 绕过了 xsd 数据集架构中所需的默认值。加载或填充后需要使用代码填写默认值。

当使用加载或填充时,您实际上并没有创建新行本身;您正在从其他地方获取行。即使 SQL 实际上是动态创建行也是如此。

比事后使用代码修复数据表更好的解决方案是将填充或加载中的 SQL 更改为使用 IsNull(x, 0) 或 IsNull(x, '')。

【讨论】:

谢谢。在这种情况下,我真的不能轻松访问 SQL。我已经发布了一些我认为可以解决问题的工作;如果您再次遇到该问题,希望它对您也有帮助。【参考方案2】:

这并没有专门使用加载或填充,但您可以通过读取数据读取器并仅在传入值不为空时设置值来轻松完成此操作。通过从SqlDataReader 获取SchemaTable,您仍然可以保持加载或填充命令的简单性,而不必写出每个列名。通过添加一个名为 Load 的 Extension 方法,该方法采用默认行参数,您可以在自己实现功能的同时保留 Load 函数的外观和感觉

使用默认行参数加载扩展方法:

''' <summary>
''' Fills a <c>System.Data.DataTable</c> with values from a data source using the supplied <c>System.Data.SqlDataReader</c>.<br/>
''' Each row is new row is given the default values from the new row and incoming nulls are ignored
''' </summary>
''' <param name="dt">DataTable to fill</param>
''' <param name="reader">A <c>System.Data.SqlDataReader</c> that provides a result set.</param>
''' <param name="defaultRow">Default values for each DataRow</param>
''' <remarks></remarks>
<Extension()> _
Public Sub Load(ByVal dt As DataTable, ByVal reader As SqlDataReader, ByVal defaultRow As DataRow)
    Dim newRow As DataRow
    'get incoming data fields
    Dim columns As List(Of String)
    columns = reader.GetSchemaTable.AsEnumerable _
                    .Select(Function(r) CStr(r("ColumnName"))).ToList()

    While reader.Read()
        'make new row and set default item array
        newRow = dt.NewRow()
        newRow.ItemArray = defaultRow.ItemArray
        'copy over new values
        For Each col As String In columns
            If Not IsDBNull(reader(col)) Then newRow(col) = reader(col)
        Next
        dt.Rows.Add(newRow)
    End While
End Sub

像这样调用你的加载方法:

Dim roleTable As New CodeSetSchemas.EntityByRoleDataTable()
Using reader As SqlDataReader = cmd.ExecuteReader()
    roleTable.Load(reader, roleTable.NewEntityByRoleRow())
End Using

【讨论】:

以上是关于加载 DataTable 时使用默认列值以避免 Null的主要内容,如果未能解决你的问题,请参考以下文章

ExtJS 4 - 当列编辑器是组合框时如何避免网格列值变为空?

排除列值以“836”开头的记录

根据 C#2.0 中的列值过滤 DataTable 行

胶水加载作业不保留红移中的默认列值

聚合列值以在 python/pyspark 中创建一个新列

熊猫填充列值以具有其他列的相似值