如何我得到这个LINQ全外连接才能正常工作?(How to I get this LINQ full

2019-09-20 02:57发布

我建立一个WPF应用程序,监视用户的计算机上的目录。 从监控的目录中的应用程序上传文件,然后保存了一些信息到一个SQLite数据库。 业务处理的一部分是不重过程,已经上传的文件,并重新上传已上传,但自上次上传已更改的文件。

我有一个建立和返回两个辅助方法List<FileMetaData>我使用LINQ -全外连接加入。 我的问题是,代码似乎并不当我用我的工作FileMetaData对象。 好像一切都应该工作,但是我在亏损,为什么它不工作。 我通常会尝试发布的其他线程上的评论,但我目前还没有对“代表”在这里做到这一点。

以下是我已经建立了一个示例,演示我的问题,如果你在运行它LINQpad 。 请确保您设置的语言为“C#程序”你点击运行按钮之前。 我应该怎么做不同的有与对象样本的工作? 万分感谢!

    void Main()
    {
        var dbItems = new List<FileMetaData>() { 
                new FileMetaData {FilePath = "C:\\Foo.txt", DbTimestamp = "1" },
                new FileMetaData {FilePath = "C:\\FooBar.txt", DbTimestamp = "3" },
            };

        var fsItems = new List<FileMetaData>() {
                new FileMetaData {FilePath = "C:\\Bar.txt", FsTimestamp = "2" },
                new FileMetaData {FilePath = "C:\\FooBar.txt", FsTimestamp = "3" },
            };

            var leftOuter = from d in dbItems
                    join f in fsItems on d.FilePath equals f.FilePath
                    into temp
                    from o in temp.DefaultIfEmpty(new FileMetaData(){})
                    select new FileMetaData { 
                        FilePath = d.FilePath, 
                        DbTimestamp = d.DbTimestamp,
                        FsTimestamp = o.FsTimestamp,
                    };

            var rightOuter = from f in fsItems
                    join d in dbItems on f.FilePath equals d.FilePath
                    into temp
                    from o in temp.DefaultIfEmpty(new FileMetaData(){})
                    select new FileMetaData { 
                        FilePath = f.FilePath, 
                        DbTimestamp = o.DbTimestamp,
                        FsTimestamp = f.FsTimestamp,
                    };

            var full = leftOuter.AsEnumerable().Union(rightOuter.AsEnumerable());

            leftOuter.Dump("Left Results");
            rightOuter.Dump("Right Results");

            full.Dump("Full Results");
    }

    // Define other methods and classes here
    public class FileMetaData
    {
        public string FilePath;
        public string DbTimestamp;
        public string FsTimestamp;
    }

编辑:

下面的答案正是我一直在寻找。 我实现了IEqualityComparer如下定义和改变了我的电话,以var full = leftOuter.Union(rightOuter, new FileMetaDataCompare()) ...

    public class FileMetaDataCompare : IEqualityComparer<FileMetaData>
    {
        public bool Equals(FileMetaData x, FileMetaData y)
        {
            var areEqual = x.FilePath == y.FilePath;
            areEqual = areEqual && x.DbTimestamp == y.DbTimestamp;
            areEqual = areEqual && x.FsTimestamp == y.FsTimestamp;

            return areEqual;
        }

        public int GetHashCode(FileMetaData obj)
        {
            var hCode = string.Concat(obj.FilePath, obj.DbTimestamp, obj.FsTimestamp);
            return hCode.GetHashCode();
        }
    }

Answer 1:

问题是, Union会给你的结果消除重复通过检查平等。 当您使用匿名类型,平等的定义是“各个领域都有平等的价值”。 在声明的类型,它将使用Equals方法。 既然你没有覆盖Equals ,它默认ReferenceEquals ,这意味着两个不同的情况下不等于不管他们的字段值。

三种方式来解决这个问题:

1)在查询中使用匿名类型,并转换为定义的类型联盟后:

var full = leftOuter.Union(rightOuter).Select(
    i=> new FileMetaData {
        FilePath = i.FilePath,
        DbTimestamp = i.DbTimestamp,
        FsTimestamp = i.FsTimestamp
    });

2)定义的IEqualityComparer<FileMetaData>定义你想(只是文件路径?所有字段?平等大公类),并通过它的一个实例,以Union()

3)覆盖Equals()GetHashCode() )中FileMetaData

2),3)将是非常相似的,但压倒一切的Equals()时,你检查的平等,而不仅仅是在这种情况下可以(会)被使用。



文章来源: How to I get this LINQ full-outer-join to function properly?