“4”和“4”在主键中冲突但在文件系统中不冲突
'4' and '4' clash in primary key but not in filesystem
有一个带主键的DataTable,用于存储文件信息。碰巧有 2 个文件的名称不同,符号为“4”和“4”(0xff14,一个 "Fullwidth Digit Four" 符号)。由于唯一性失败,DataTable 无法同时包含它们。但是,在 Windows 文件系统中,它们似乎能够毫无问题地共存。
该行为似乎不依赖于语言环境设置,我将 "Region&Language->Formats->Format" 从英语更改为日语,也进行了 "language for non-unicode programs" 更改。语言环境打印为 "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)
PS:语言环境被视为:
通过使用 DataType = typeof(object)
你 "disable" 字符串规范化。字符串相等性仍然用于比较。不知道有没有其他副作用
更复杂的解决方案:为 string
class:
实施 "wrapper"
public class MyString : IEquatable<MyString>, IComparable, IComparable<MyString>
{
public static readonly StringComparer Comparer = StringComparer.InvariantCultureIgnoreCase;
public readonly string Value;
public MyString(string value)
{
Value = value;
}
public static implicit operator MyString(string value)
{
return new MyString(value);
}
public static implicit operator string(MyString value)
{
return value != null ? value.Value : null;
}
public override int GetHashCode()
{
return Comparer.GetHashCode(Value);
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is MyString))
{
return false;
}
return Comparer.Equals(Value, ((MyString)obj).Value);
}
public override string ToString()
{
return Value != null ? Value.ToString() : null;
}
public bool Equals(MyString other)
{
if (other == null)
{
return false;
}
return Comparer.Equals(Value, other.Value);
}
public int CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
return CompareTo((MyString)obj);
}
public int CompareTo(MyString other)
{
if (other == null)
{
return 1;
}
return Comparer.Compare(Value, other.Value);
}
}
然后:
var changes = new DataTable("Rows");
var column = new DataColumn { DataType = typeof(MyString), ColumnName = "File" };
changes.Columns.Add(column);
var primKey = new DataColumn[1];
primKey[0] = column;
changes.PrimaryKey = primKey;
changes.Rows.Add((MyString)"a");
changes.Rows.Add((MyString)"4.txt");
try
{
changes.Rows.Add((MyString)"4.txt"); // throws the exception
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
var row = changes.Rows.Find((MyString)"A");
有一个带主键的DataTable,用于存储文件信息。碰巧有 2 个文件的名称不同,符号为“4”和“4”(0xff14,一个 "Fullwidth Digit Four" 符号)。由于唯一性失败,DataTable 无法同时包含它们。但是,在 Windows 文件系统中,它们似乎能够毫无问题地共存。
该行为似乎不依赖于语言环境设置,我将 "Region&Language->Formats->Format" 从英语更改为日语,也进行了 "language for non-unicode programs" 更改。语言环境打印为 "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)
PS:语言环境被视为:
通过使用 DataType = typeof(object)
你 "disable" 字符串规范化。字符串相等性仍然用于比较。不知道有没有其他副作用
更复杂的解决方案:为 string
class:
public class MyString : IEquatable<MyString>, IComparable, IComparable<MyString>
{
public static readonly StringComparer Comparer = StringComparer.InvariantCultureIgnoreCase;
public readonly string Value;
public MyString(string value)
{
Value = value;
}
public static implicit operator MyString(string value)
{
return new MyString(value);
}
public static implicit operator string(MyString value)
{
return value != null ? value.Value : null;
}
public override int GetHashCode()
{
return Comparer.GetHashCode(Value);
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is MyString))
{
return false;
}
return Comparer.Equals(Value, ((MyString)obj).Value);
}
public override string ToString()
{
return Value != null ? Value.ToString() : null;
}
public bool Equals(MyString other)
{
if (other == null)
{
return false;
}
return Comparer.Equals(Value, other.Value);
}
public int CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
return CompareTo((MyString)obj);
}
public int CompareTo(MyString other)
{
if (other == null)
{
return 1;
}
return Comparer.Compare(Value, other.Value);
}
}
然后:
var changes = new DataTable("Rows");
var column = new DataColumn { DataType = typeof(MyString), ColumnName = "File" };
changes.Columns.Add(column);
var primKey = new DataColumn[1];
primKey[0] = column;
changes.PrimaryKey = primKey;
changes.Rows.Add((MyString)"a");
changes.Rows.Add((MyString)"4.txt");
try
{
changes.Rows.Add((MyString)"4.txt"); // throws the exception
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
var row = changes.Rows.Find((MyString)"A");