65.9K
CodeProject is changing. Read more.
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3 votes)

Aug 2, 2016

CPOL

2 min read

viewsIcon

11569

downloadIcon

115

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 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 l1 = new List();
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 l2 = new List();
l2.Add(new Person(){ Id=1 , FirstName="david" , LastName="zenou" , Age=35});

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 l1 = new List();
l1.Add(new Person(){ Id=1 , FirstName="david" , LastName="zenou" , Age=35});

List l2 = new List();
l2.Add(new Person(){ Id=1 , FirstName="david" , LastName="zenou" , Age=35});
l2.Add(new Person(){ Id=2 , FirstName="nathan" , LastName="zenou" , Age=3});

Here if we compare l1 to l2, we can say that there is one added row (Id = 2).(Easy to detect)

Last case :

List l1 = new List();
l1.Add(new Person(){ Id=1 , FirstName="david" , LastName="zenou" , Age=35});

List l2 = new List();
l2.Add(new Person(){ Id=1 , FirstName="david1" , LastName="zenou" , Age=36});

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 comparerEntity). For this example we need to implement the entity comarer IEqualityComparer :

   public class PersonEntityComparer : IEqualityComparer
    {
        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;
        }
    }

parameter 4 : an entity primary key comparer (IEqualityComparer comparerKeyEntity)

public class PersonEntityPrimaryKeyComparer : IEqualityComparer
    {
        public bool Equals(Person x, Person y)
        {
            return (x.Id == y.Id);
        }

        public int GetHashCode(Person obj)
        {
            return obj.Id;
        }
    }

How to exploit the extension method ? In your program, you must do that :

 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 l1 = new List();
		l1.Add(new Person(){ Id=1 , FirstName="david" , LastName="zenou" , Age=35});

		List l2 = new List();
		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 compareResult = l1.Compare(l2, entityComparer, primarykeyComparer);
		 
		 //Here in compareResult , you get 3 IEnumerable collecitons (inserted elements, updated elements, deleted elements)
	 }

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
    {
        public IEnumerable Inserted { get; set; }
        public IEnumerable Updated { get; set; }
        public IEnumerable Removed { get; set; }
    }

    public static class IEnumerableExtensions
    {
        public static CompareResult Compare(this IEnumerable left, IEnumerable right, IEqualityComparer comparerEntity, IEqualityComparer comparerKey)
        {
            CompareResult compareResult = new CompareResult();

            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 sameElementsRight = right.Intersect(left, comparerEntity);
            IEnumerable sameElementsLeft = left.Intersect(right, comparerEntity);

            Console.WriteLine("===================== Equals elements : ===========================");
            foreach (T t in sameElementsRight)
                Console.WriteLine(t);


            IEnumerable sameKeyElementsRight = right.Intersect(left, comparerKey);
            IEnumerable sameKeyElementsLeft = left.Intersect(right, comparerKey);

            IEnumerable ElementsUpdtated = sameKeyElementsRight.Except(sameElementsRight);
            IEnumerable elementsToUpdtate = sameKeyElementsLeft.Except(sameElementsLeft);

            Console.WriteLine("===================== Updated Elements : ===========================");
            foreach (T t in ElementsUpdtated)
                Console.WriteLine(t);


            IEnumerable 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 elementDifferentsKeyRights = right.Except(left, comparerKey);

            IEnumerable 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;
        }
    }

}
 

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.