C# 比较相同用户定义类型的两个列表
我有一个这样的数据集C# 比较相同用户定义类型的两个列表,c#,performance,linq,C#,Performance,Linq,我有一个这样的数据集 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:wind
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 for basic 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();
}
}
class cve\u CPE比较器:IEqualityComparer
{
公共布尔等于(cve_cpe x,cve_cpe y)
{
if(object.ReferenceEquals(x,y))
返回true;
如果(x==null | | y==null)
返回false;
返回x.cpeid==y.cpeid&&x.cveid==y.cveid;
}
公共int GetHashCode(cve_cpe obj)
{
返回obj.cveid.GetHashCode()^obj.cpeid.GetHashCode();
}
}
但这并不简单。我尝试了各种关于实现GetHashCode的建议,在entity和db中设置适当的键,手动从db中删除重复项,但根本不起作用。我错过了什么
因此,基本上,我希望linq。除了
之外,它会给我列表中那些在db中不存在的条目,即忽略那些在db数据列表中具有相同组合的cveid
和cpeid
非常有趣的是,这件事与许多其他我的用户定义类型一起工作,它们的风格是IEqualityComparer
(逻辑上实现相同),所以想知道我做错了什么吗?是用这些符号串的值吗
更新
所以它现在可以工作了,事实证明,这是因为实体和modelbuilder中的pk配置错误,解决了这个问题。
但是现在我想知道为什么
LINQ。除了
甚至担心主键,特别是当我给它提供一个定制的IEqualityComparer
时 我无意中进入了这个页面,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();
您是想在数据库中执行except(使用EF查询)还是在内存中已经物化的列表中执行?它正在内存中的
物化列表中执行。您的相等比较器将{cpeid,cveid}
对视为定义唯一性。但是实体PK(唯一键)是{cveid,LastEdited}
。显然其中一个是错误的,必须纠正。是的,就是这样,错误的pk配置。现在可以了。谢谢,但你能帮我理解一下,为什么它(linq to entity)还要为PK操心呢?当我在内存中处理分离列表时?我的意思是,在iQualityComparer中,我从不关心PKIt在您的独立列表中的工作。但问题是它对映射到\u add
的假设是错误的,所以我想问题是当您真正尝试将它们添加到数据库中时,您会遇到唯一的约束冲突。甚至在将它们添加(附加)到上下文时,因为EF在内存中内部维护唯一的键索引。
public int GetHashCode(cve_cpe obj)
{
return obj.cveid.GetHashCode() * 11 /*Any prime number*/ ^ obj.cpeid.GetHashCode();
}