Introduction
You often need to compare some collections of entities , when you compare 2 collections, you need to know wich elements are added, wich element are deleted, and wich elements are updated.
Background
Generally, Linq powerfull allows you to find this differences with some simple queries. Today , i try to imagine a generic structure implementation who allow you to do that enough easily. I give you a simple example to use it , and the implementation.
Using the code
Imagine, you have 2 IEnumerable<t> collections , where T is a Person entity in my example :
public class Person
{
public int Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int Age {get;set;}
}
So, First case, you can have :
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});
</person></person></person></person>
Here if we compare l1 to l2, we can say that there is one deleted row (Id = 2). (Easy to detect).
Second case, you can have :
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});
</person></person></person></person>
Here if we compare l1 to l2, we can say that there is one added row (Id = 2).(Easy to detect)
Last case :
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});
</person></person></person></person>
In this exemple Ids are the same but Firstname and Age are differents, so now we say that the row was updated. (First we checked the Primary keys of the collection, we saw there are eqauls, then we checked others properies of the row and we saw the diffrences)
So to use my class extension, you need to provides 4 parameters : parameter 1 : compare From Collection parameter 2 : compare To Collection parameter 3 : an entity comparer (IEqualityComparer<t> comparerEntity). For this example we need to implement the entity comarer IEqualityComparer<person></person>
:
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;
}
}
</person>
parameter 4 : an entity primary key comparer (IEqualityComparer<t> comparerKeyEntity)</t>
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;
}
}
</person>
How to exploit the extension method ? In your program, you must do that :
static void Main(string[] args)
{
PersonEntityComparer entityComparer = new PersonEntityComparer();
PersonEntityPrimaryKeyComparer primarykeyComparer = new PersonEntityPrimaryKeyComparer();
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});
CompareResult<person> compareResult = l1.Compare(l2, entityComparer, primarykeyComparer);
}
</t></person></person></person></person></person>
Now watch the code of the comparer extension ComparerResult.cs file :
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);
Console.WriteLine("===================== Equals elements : ===========================");
foreach (T t in sameElementsRight)
Console.WriteLine(t);
IEnumerable<t> sameKeyElementsRight = right.Intersect(left, comparerKey);
IEnumerable<t> sameKeyElementsLeft = left.Intersect(right, comparerKey);
IEnumerable<t> ElementsUpdtated = sameKeyElementsRight.Except(sameElementsRight);
IEnumerable<t> elementsToUpdtate = sameKeyElementsLeft.Except(sameElementsLeft);
Console.WriteLine("===================== Updated Elements : ===========================");
foreach (T t in ElementsUpdtated)
Console.WriteLine(t);
IEnumerable<t> ElementRemoved = left.Except(right, comparerEntity);
ElementRemoved = ElementRemoved.Where(e => !elementsToUpdtate.Contains(e, comparerEntity));
Console.WriteLine("===================== Deleted Elements : ===========================");
foreach (T t in ElementRemoved)
Console.WriteLine(t);
IEnumerable<t> elementDifferentsKeyRights = right.Except(left, comparerKey);
IEnumerable<t> ElementAdded = right.Except(left, comparerEntity);
ElementAdded = ElementAdded.Where(e => elementDifferentsKeyRights.Contains(e, comparerEntity));
Console.WriteLine("===================== Added Elements : ===========================");
foreach (T t in ElementAdded)
Console.WriteLine(t);
compareResult.Inserted = ElementAdded;
compareResult.Updated = ElementsUpdtated;
compareResult.Removed = ElementRemoved;
return compareResult;
}
}
}
</t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t></t>
Points of Interest
Find a generic solution to compare any entities list
History
Keep a running update of any changes or improvements you've made here.