Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
2 Aug 2016CPOL2 min read 10.9K   114   7   2
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Several
France France
Fan of .NET Technologies
Go to see my blog : http://davidzenou.blogspot.com/2009/01/david.html

Comments and Discussions

 
SuggestionSuggestion: Use Linq Pin
bfrthekid992-Aug-16 14:48
bfrthekid992-Aug-16 14:48 
GeneralRe: Suggestion: Use Linq Pin
Dav Zen2-Aug-16 20:40
Dav Zen2-Aug-16 20:40 
I know distinct and union operators , it was my first reflex to try to use them , but there are so much particulary cases that i didn t find the generic solution , can you post your solution of your implementation , i m interested to see it.

Best regards
Si tu aimes ce que tu fais , tu finis par réussir !
(french proverb of David Zenou)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.