但是 find 方法“自动”修剪我的密钥并找到存储的
无论如何实体。
我不相信会发生修剪。Find
uses a SingleOrDefault
内部查询,换句话说:当您调用...
set.Find("ABCDE "); // including the trailing blank
...它使用这个 LINQ 查询:
set.SingleOrDefault(key => key == "ABCDE "); // including the trailing blank
问题出在数据库中,结果取决于排序顺序、语言、大写/小写字母设置、重音等。string
数据库中的关键字段(nvarchar(10)
例如)。
例如,如果您使用标准Latin1_General
SQL Server 中键的排序顺序"ABCDE" and "ABCDE "(尾随空白)相同,您无法创建以这些值作为主键的两行。甚至"ABCDE" and "abcde"是相同的(如果您没有在 SQL Server 中设置区分大小写字母)。
同时这意味着也查询string
columns 将返回所有匹配的行 - 与数据库中该列的排序顺序匹配。查询为"ABCDE "尾随空白只会返回一条记录"ABCDE"没有尾随空白。
到目前为止,对于所有涉及字符串的 LINQ to Entities 查询来说,这是“正常”行为。
现在,正如您所发现的那样,ObjectContext 似乎不知道数据库中配置的排序顺序,并使用正常的 .NET 字符串比较,其中带尾随空格的字符串和不带尾随空格的字符串是不同的。
我不知道是否可以告诉上下文使用与数据库相同的字符串比较。我有些怀疑这是否可能,因为 .NET 世界和关系数据库世界太不同了。某些排序顺序可能很特殊,仅在数据库中可用,而在 .NET 中根本不可用,反之亦然。此外,除了 SQL Server 之外,还有其他数据库必须受到实体框架的支持,并且这些数据库可能有自己的排序系统。
对于您的具体情况 - 也许总是当您有string
键 - 问题的可能解决方法是将实体的 key 属性设置为更新为从数据库返回的对象的键:
toUpdate.Id = current.Id;
_context.Entry(current).CurrentValues.SetValues(toUpdate);
或者更一般地说,在您的代码上下文中:
//...
var current = _context.Set<T>().Find(values);
if (current != null)
{
foreach (var keyName in keyNames)
{
var currentValue = type.GetProperty(keyName).GetValue(current, null);
type.GetProperty(keyName).SetValue(toUpdate, currentValue, null);
}
_context.Entry(current).CurrentValues.SetValues(toUpdate);
}
toUpdate
不得附加到上下文才能使其正常工作。
这是一个错误吗?我不知道。至少这是 .NET 和关系数据库世界之间不匹配的结果,也是避免的一个很好的理由string
首先是关键列/属性。