【发布时间】:2017-01-28 11:59:54
【问题描述】:
我有一个这样的数据集
cpeid cveid LastEdited
cpe:/o:microsoft:windows_8.1:- CVE-2015-0001 2017-01-28 17:03:21.197
cpe:/o:microsoft:windows_8:- CVE-2015-0001 2017-01-28 17:03:21.197
cpe:/o:microsoft:windows_rt:-:gold CVE-2015-0001 2017-01-28 17:03:21.197
还有一个像这样的支持实体:
public partial class cve_cpe
{
[StringLength(250)]
public string cpeid { get; set; }
[Key]
[Column(Order = 0)]
[StringLength(250)]
public string cveid { get; set; }
[Key]
[Column(Order = 1, TypeName = "smalldatetime")]
public DateTime LastEdited { get; set; }
}
我正在从一个简单的 c# 控制台应用程序中使用 entityframework 对数据库进行基本的 crud。在代码中的某处我这样做:
var mappings_to_add = distinct_mappings_from_file
.Except(all_mappings, new cve_cpeComparer())
.ToList();
我的IEqualityComparer 实现是:
class cve_cpeComparer : IEqualityComparer<cve_cpe>
{
public bool Equals(cve_cpe x, cve_cpe y)
{
if (object.ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
return x.cpeid == y.cpeid && x.cveid == y.cveid;
}
public int GetHashCode(cve_cpe obj)
{
return obj.cveid.GetHashCode() ^ obj.cpeid.GetHashCode();
}
}
但它不会简单地工作。我尝试了各种关于实现 GetHashCode、在实体和数据库中设置正确键、手动从数据库中删除重复项的建议,但它根本不起作用。我在这里错过了什么?
所以基本上,我希望 linq .Except 给我列表中那些不存在于 db 中的条目,即忽略那些在 db 数据列表中已经存在 cveid 和 cpeid 的相同组合的条目。
有趣的是,这个东西可以与我的许多其他用户定义类型一起使用,它们具有IEqualityComparer 的风格(逻辑实现相同),所以想知道我做错了什么?是不是跟这些带符号的字符串的值有关?
更新
所以它现在可以工作了,事实证明,这是因为实体和模型构建器中的 pk 配置错误,修复它可以解决问题。
但是现在我想知道为什么LINQ .Except 甚至担心主键,特别是当我给它喂一个自定义的IEqualityComparer 时?
【问题讨论】:
-
您是要在数据库中执行 except(使用 EF 查询)还是在内存中已经物化的列表中执行?
-
它正在内存中的
materialized list中执行 -
您的相等比较器认为
{ cpeid, cveid }对定义了唯一性。但是实体 PK(唯一键)是{ cveid, LastEdited }。显然其中一个是错误的,必须纠正。 -
是的,就是这样,错误的 pk 配置。现在可以了。谢谢,但你能帮我理解一下,为什么它(linq-to-entity)甚至会为 PK 烦恼?因为我正在处理内存中的分离列表?我的意思是在 IEqualityComparer 中,我从不关心 PK
-
它适用于您的分离列表。但问题是它对
mappings_to_add做出了错误的假设,所以我想问题是当您真正尝试将它们添加到数据库时,您会遇到唯一约束违规。甚至在将它们添加(附加)到上下文时,因为 EF 在内部维护内存中的唯一键索引。
标签: c# performance linq