【发布时间】:2018-10-26 13:03:01
【问题描述】:
有一个带有主键的 DataTable 来存储有关文件的信息。碰巧有两个文件名称不同,符号为“4”和“4”(0xff14,“全角四位”符号)。由于唯一性失败,DataTable 未能将它们都包括在内。但是,在 Windows 文件系统中,它们似乎可以毫无问题地共存。
该行为似乎不依赖于区域设置,我将“区域和语言->格式->格式”从英语更改为日语,“非 unicode 程序的语言”也发生了变化。语言环境打印为“jp-JP”、“en-GB”。总是一样的结果。
问题:
- 有什么方法可以减少干扰?我可以切换到使用容器而不是 System.Data.* 但我想避免它。是否可以为列定义自定义比较器或更好地检查唯一性?启用区分大小写(这将解决这个问题)会导致其他问题。
- 是否有可能某些全局设置可以在不重建软件的情况下修复它?
失败的演示程序:
using System;
using System.Data;
namespace DataTableUniqueness
{
class Program
{
static void Main(string[] args)
{
var changes = new DataTable("Rows");
var column = new DataColumn { DataType = Type.GetType("System.String"), ColumnName = "File" };
changes.Columns.Add(column);
var primKey = new DataColumn[1];
primKey[0] = column;
changes.PrimaryKey = primKey;
changes.Rows.Add("4.txt");
try
{
changes.Rows.Add("4.txt"); // throws the exception
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
}
}
}
例外
Exception: System.Data.ConstraintException: Column 'File' is constrained to be unique. Value '4.txt' is already present.
at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action)
at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent)
at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean suppressEnsurePropertyChanged, Int32 position, Boolean fireEvent, Exception& deferredException)
at System.Data.DataTable.InsertRow(DataRow row, Int64 proposedID, Int32 pos, Boolean fireEvent)
at System.Data.DataRowCollection.Add(Object[] values)
【问题讨论】:
-
这是一个有趣的行为,也许
change.Rows.Add("someFile")将 unicode 字符解析成别的东西? -
@mjwills,没有底层数据库,只是在内存数据中,如示例中
-
这根本不能回答您的问题,但作为一种解决方法(如果您没有找到解决方案),您可以选择通过唯一 ID 引用您的文件,而不是使用 msdn.microsoft.com/en-us/library/aa364952(VS.85).aspx即让它们以您或您的用户希望选择的任何时髦文件名存在于磁盘上,但将它们添加到数据表中,然后通过 ID 窗口已经为它们查找它们。
-
也许额外字节中的值的 ASCII 表示是不可打印的字符,因此是空格。在 DataTable 中进行比较时,值解析为“4”?
-
显然是因为
"4".Normalize(NormalizationForm.FormKC)和"4".Normalize(NormalizationForm.FormKD)都等于"4"。现在的问题是如何禁用它...
标签: c# windows unicode system.data