在编程中,经常需要比较两个集合以找出它们之间的差异,比如哪些元素被添加了,哪些被删除了,以及哪些被更新了。幸运的是,LINQ提供了强大的查询功能,使得这一任务变得相对简单。本文将介绍一种通用的结构实现,以便轻松地完成这项工作,并提供示例代码来演示其用法。
LINQ(Language Integrated Query)是.NET框架中一个强大的查询功能,它允许开发者以声明式的方式处理数据集合。通过LINQ,可以轻松地找出两个集合之间的差异。本文将提供一个简单的示例,展示如何实现这一功能。
假设有两个IEnumerable
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
接下来,可以通过以下步骤来比较两个集合:
List<Person> l1 = new List<Person>();
l1.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
l1.Add(new Person() { Id = 2, FirstName = "nathan", LastName = "zenou", Age = 3 });
List<Person> l2 = new List<Person>();
l2.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
在这个例子中,如果比较l1和l2,可以发现有一个被删除的行(Id = 2)。
List<Person> l1 = new List<Person>();
l1.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
List<Person> l2 = new List<Person>();
l2.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
l2.Add(new Person() { Id = 2, FirstName = "nathan", LastName = "zenou", Age = 3 });
在这个例子中,如果比较l1和l2,可以发现有一个新增的行(Id = 2)。
List<Person> l1 = new List<Person>();
l1.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
List<Person> l2 = new List<Person>();
l2.Add(new Person() { Id = 1, FirstName = "david1", LastName = "zenou", Age = 36 });
在这个例子中,虽然Id相同,但是FirstName和Age不同,所以可以说这一行被更新了。
要使用类扩展,需要提供四个参数:第一个参数是比较的源集合,第二个参数是比较的目标集合,第三个参数是一个实体比较器(IEqualityComparer
public class PersonEntityComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return (x.Id == y.Id) && x.FirstName.Equals(y.FirstName) && x.LastName.Equals(y.LastName) && x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj.Id;
}
}
public class PersonEntityPrimaryKeyComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return (x.Id == y.Id);
}
public int GetHashCode(Person obj)
{
return obj.Id;
}
}
static void Main(string[] args)
{
// 1. 创建PersonEntityComparer实例
PersonEntityComparer entityComparer = new PersonEntityComparer();
// 2. 创建PersonEntityPrimaryKeyComparer实例
PersonEntityPrimaryKeyComparer primarykeyComparer = new PersonEntityPrimaryKeyComparer();
// 3. 创建两个已填充或空的集合
List<Person> l1 = new List<Person>();
l1.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
List<Person> l2 = new List<Person>();
l2.Add(new Person() { Id = 1, FirstName = "david", LastName = "zenou", Age = 35 });
l2.Add(new Person() { Id = 2, FirstName = "nathan", LastName = "zenou", Age = 3 });
// 4. 调用比较扩展
CompareResult<Person> compareResult = l1.Compare(l2, entityComparer, primarykeyComparer);
// 在compareResult中,将得到三个IEnumerable集合(插入的元素、更新的元素、删除的元素)
}
以下是ComparerResult.cs文件中的比较器扩展的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class CompareResult<T>
{
public IEnumerable<T> Inserted { get; set; }
public IEnumerable<T> Updated { get; set; }
public IEnumerable<T> Removed { get; set; }
}
public static class IEnumerableExtensions
{
public static CompareResult<T> Compare<T>(this IEnumerable<T> left, IEnumerable<T> right, IEqualityComparer<T> comparerEntity, IEqualityComparer<T> comparerKey)
{
CompareResult<T> compareResult = new CompareResult<T>();
bool isLeftEmptyOrNull = (left == null || !left.Any());
bool isRightEmptyOrNull = (right == null || !right.Any());
if (isLeftEmptyOrNull && isRightEmptyOrNull)
return compareResult;
else if (isLeftEmptyOrNull && !isRightEmptyOrNull)
{
compareResult.Inserted = right;
return compareResult;
}
else if (!isLeftEmptyOrNull && isRightEmptyOrNull)
{
compareResult.Removed = left;
return compareResult;
}
// 相同的元素
IEnumerable<T> sameElementsRight = right.Intersect(left, comparerEntity);
IEnumerable<T> sameElementsLeft = left.Intersect(right, comparerEntity);
// 相同的主键元素
IEnumerable<T> sameKeyElementsRight = right.Intersect(left, comparerKey);
IEnumerable<T> sameKeyElementsLeft = left.Intersect(right, comparerKey);
// 更新的元素
IEnumerable<T> ElementsUpdtated = sameKeyElementsRight.Except(sameElementsRight);
IEnumerable<T> elementsToUpdate = sameKeyElementsLeft.Except(sameElementsLeft);
// 删除的元素
IEnumerable<T> ElementRemoved = left.Except(right, comparerEntity);
ElementRemoved = ElementRemoved.Where(e => !elementsToUpdate.Contains(e, comparerEntity));
// 新增的元素
IEnumerable<T> elementDifferentsKeyRights = right.Except(left, comparerKey);
IEnumerable<T> ElementAdded = right.Except(left, comparerEntity);
ElementAdded = ElementAdded.Where(e => elementDifferentsKeyRights.Contains(e, comparerEntity));
compareResult.Inserted = ElementAdded;
compareResult.Updated = ElementsUpdtated;
compareResult.Removed = ElementRemoved;
return compareResult;
}
}
}