如何让 AllowDBNull 为 GUID 工作?

Posted

技术标签:

【中文标题】如何让 AllowDBNull 为 GUID 工作?【英文标题】:How can I make AllowDBNull work for GUID? 【发布时间】:2021-11-28 00:54:08 【问题描述】:

我正在使用 DataColumn 为 DataTable 创建一个新列。我使用AllowDBNull 指定列可以有NULL 值。

这很好用,除非我有一个 uniqueidentifier 类型的列我正在做的地方

public static Type GetClrType(SqlDbType sqlType, bool isNullable)

  switch (sqlType)
  
     case SqlDbType.UniqueIdentifier:
        return isNullable ? typeof(Guid?) : typeof(Guid);
     ......other types......
  

DataColumn columnValue = DataColumn(column.Name, GetClrType(columnType, IsNullable))
dt.Columns.Add(columnValue);

我在尝试使用 CsvHelper 加载数据表并看到错误时遇到问题

未处理的异常。 System.AggregateException:一个或多个错误 发生了。 (Guid 应包含 32 位数字和 4 个破折号 (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。无法将<NULL> 存储在 MyGuIdColumn 列。预期类型是 Guid。)

感谢任何解决此问题的帮助。

更新(更多详情):

CSV 文件记录是这样的:

Id (uniqueidentifier, Not null)      | Name (Nvarchar, null) | OtherId (uniqueidentifier, null) 
deb01846-c208-ec01-a4e4-005056bc1234 | TestName              | NULL

我正在读取这样的 csv 文件:

var dt = new DataTable();
// get the table def -> will have all column props
foreach (column in columns)

  var columnType = column.DataType; // (uniqueidentifier) I get this value from table schema
  var dataType = Map.GetClrType(columnType); // (GUID) from a SqlDbType -> c# map
  DataColumn columnValue = new DataColumn(column.Name, dataType);
  columnValue.AllowDBNull = true; // comes from IS Nullable column of table schema
  columnValue.DefaultValue = if is nullable => Guid.Empty/Null/DbNUll.Value; // tried these
  dt.Columns.Add(columnValue);


using (var reader = new StreamReader(filePath))
using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))

   using (var dr = new CsvDataReader(csv))
   
      dt.Load(dr); // error here
      return dt;
    

【问题讨论】:

请分享minimal reproducible example。 分享异常代码 更新了更多细节 您的架构标记为NOT NULL,并且您在.NET 端指定typeof(Guid)(不是typeof(Guid?))。这些都不支持NULL @Flydog57 更新了我的帖子。我确实有你提到的方式。 【参考方案1】:

哦.. 我花了一段时间才看到它,但问题是,我怀疑您的 CSV 文件在 OtherId 列中确实包含字符串 "NULL";你必须告诉 CSVH “NULL”意味着DBNull.Value

以下代码将读取您发布到 github 的 CSV:

        using var reader = new CsvReader(File.OpenText(_openFileDialog.FileName), conf);
        using var dataReader = new CsvDataReader(reader);

        var dt = dataReader.GetSchemaTable(); //the schema table is huge, get CSVH to make it

        //the schema table describes the file layout
        dt.Rows[0]["DataType"] = typeof(Guid); //first column is a GUID
        dt.Rows[0]["AllowDBNull"] = false;     //and not null (default true)
        dt.Rows[2]["DataType"] = typeof(Guid); //third column is also a GUID

        //tell CSVH that a string of "NULL" is a null value
        var tco = new CsvHelper.TypeConversion.TypeConverterOptions();
        tco.NullValues.Add("NULL");
        reader.Context.TypeConverterOptionsCache.AddOptions<string>(tco);


        var ddt = new DataTable();
        ddt.Load(dataReader);

现在 ddt 包含一个用于 OtherId 的 Guid 列,并且它允许空 guid

您不必事先知道列类型。在var dt = dataReader.GetSchemaTable();var dt = dataReader.GetSchemaTable(); 行执行时,dt 将具有列名。如果标题与您发布的一样,那么当您获得架构时,但在您读取任何数据之前,您将能够枚举架构表并对其进行调整:

ps;我对你的 CSV 有点作弊,因为我懒得查找如何将管道设置为分隔符 - 读者练习(哈哈):

【讨论】:

这对我很有用。我现在可以加载数据了。即使数据已成功加载到表中,我仍然在我的 catch 块中看到 System.Data.ConstraintException: Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.。我会调查的,但我的问题现在已经解决了。感谢您的帮助。 检查主键列中的mills;你可以调用ddt.GetErrors 来获取所有错误的行,DataRow 本身有一个 RowError 属性可以告诉你什么是错误的

以上是关于如何让 AllowDBNull 为 GUID 工作?的主要内容,如果未能解决你的问题,请参考以下文章

即使 AllowDBNull = False,数据集也允许 Null 值?

如何处理泛型函数中的空 Guid?

使用 JSON 时如何让 ServiceStack 用破折号格式化 Guid?

如何在pyspark中将GUID转换为整数

如何使Recovery分区正常工作

如何将挂载点的卷 GUID 转换为实际路径?