比较两个相同用户定义类型的列表

时间:2017-01-28 11:59:54

标签: 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: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中尚未存在的条目,即忽略具有cveidcpeid相同组合的条目已经在数据库数据列表中。

有趣的是,这个东西适用于我的许多其他用户定义类型,其风格为IEqualityComparer(逻辑上实现相同),所以想知道我做错了什么?是否带有符号的这些字符串的值?

更新

现在它正常运行,事实证明,这是因为实体和模型构建器中的pk配置错误,修复了解决问题的方法。 但现在我想知道为什么LINQ .Except甚至担心主键,特别是当我给它一个自定义的IEqualityComparer时?

1 个答案:

答案 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();
}