我有一个像这样的数据集
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的建议,在实体和db中设置正确的密钥,手动从db中删除重复项,但它根本不起作用。我在这里缺少什么?
所以基本上,我希望linq .Except
能够从列表中给出那些db中尚未存在的条目,即忽略具有cveid
和cpeid
相同组合的条目已经在数据库数据列表中。
有趣的是,这个东西适用于我的许多其他用户定义类型,其风格为IEqualityComparer
(逻辑上实现相同),所以想知道我做错了什么?是否带有符号的这些字符串的值?
更新
现在它正常运行,事实证明,这是因为实体和模型构建器中的pk配置错误,修复了解决问题的方法。
但现在我想知道为什么LINQ .Except
甚至担心主键,特别是当我给它一个自定义的IEqualityComparer
时?
答案 0 :(得分:0)
我不小心在这个IEqualityComparer.GetHashCode
实施引起我注意的页面中结束了。想象一下以下代码:
var list = new List<cve_cpe>
{
new cve_cpe { cpeid = "1", cveid = "2" },
new cve_cpe { cpeid = "2", cveid = "1" }
};
var result = list.Except(list, new cve_cpeComparer()).ToList();
如果执行上面的代码,Equals
方法将被调用4次,因为GetHashCode
将为两个对象返回相同的值。通过更改GetHashCode
的实现,可以将其减少到2倍:
public int GetHashCode(cve_cpe obj)
{
return obj.cveid.GetHashCode() * 11 /*Any prime number*/ ^ obj.cpeid.GetHashCode();
}