Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Entity List<T> data comparer (Inserted , Deleted , Updated items)

0.00/5 (No votes)
2 Aug 2016 1  
Tool collection comparer

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 :

C#
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 :

C#
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 :

C#
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 :

C#
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> :

C#
   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>

C#
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 :

C#
 static void Main(string[] args)
     {
		//1- create one instance of PersonEntityComparer
		PersonEntityComparer entityComparer = new PersonEntityComparer();
		//2- create one instance of PersonEntityPrimaryKeyComparer
		PersonEntityPrimaryKeyComparer primarykeyComparer = new PersonEntityPrimaryKeyComparer();	
		//3- create 2 filled or empty collections
		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});
		
		//1-call my compare extention
		 CompareResult<person> compareResult = l1.Compare(l2, entityComparer, primarykeyComparer);
		 
		 //Here in compareResult , you get 3 IEnumerable<t> collecitons (inserted elements, updated elements, deleted elements)
	 }
</t></person></person></person></person></person>

Now watch the code of the comparer extension ComparerResult.cs file :

C#
 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;
            }

            //same elements
            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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here