Thursday, June 27, 2013

Linq to Entities (or Entity Framework) - Find index of row matching condition in entity set (DbSet/ ObjectSet)

This article aims to explain how to find the index of a row matching a particular condition in DbSet/ ObjectSet using Linq to Entities.

While working with Entity Framework (at least till Entity Framework 5), and Linq-to-entities, I realized it doesn't have support to find index of row within the DbSet for obvious reasons. And so I thought to write a method manually. There are many approaches for the same, and different developers might have implemented different approaches. I found the one I implemented below as more performance optimized.

Say, for example, you have an entity set "Cities". There exists, thousands of rows in this table. You need to sort the cities by their name, and want to find index of a particular city within that ordered collection.

One instance of such need is to have paging implemented in your site, and you want your user to jump to the page containing record of a particular city by keeping paging intact.

The approach is to - First check if that particular city exists in the "Cities" collection or not.
If it exists, call the below FindIndex method:

Also, take a note of loopCapacity variable in below code. In below example, it means, the final "for loop" to find and calculate the index will be started only after a bunch of 100 records are found. Here, these 100 records contain that particular record (i.e. city) which we are looking for.  

public int FindIndex(String CityName)
        {
            int index = 0;
            int totalRecords = db.Cities.Count();
            int halfCount = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(totalRecords / 2))) + 1;
            int loopCapacity = 100;
            int recordsToSkip = 0;
            if (totalRecords > 0)
            {
                bool nextIteration = true;
                while (nextIteration)
                {
                    for (int counter = 0; counter < 2; counter++)
                    {
                        recordsToSkip = recordsToSkip + (counter * halfCount);
                        if (db.Cities.OrderBy(c => c.CityName).Skip(recordsToSkip).Take(halfCount).Where(c => c.CityName == CityName).Count() > 0)
                        {
                            if (halfCount > loopCapacity)
                            {
                                totalRecords = totalRecords - (halfCount * 1);
                                halfCount = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(totalRecords / 2))) + 1;
                                nextIteration = true;
                                break;
                            }
                            else
                            {
                                foreach (Cities city in db.Cities.OrderBy(c => c.CityName).Skip(recordsToSkip).Take(halfCount))
                                {
                                    if (city.CityName == CityName)
                                    {
                                        index = index + 1;
                                        index = recordsToSkip + index;
                                        break;
                                    }
                                    else
                                    {
                                        index = index + 1;
                                    }
                                }
                                nextIteration = false;
                                break;
                            }
                        }
                        else
                        {
                            nextIteration = true;
                        }
                    }
                }
            }
            return index;
        }


Hope this helps!

Do let me know if anything is unclear, or if you need explanation for any part of code

Thanks

No comments:

Post a Comment

Thanks for visiting my blog.
However, if this helped you in any way, please take a moment to write a comment.

Thanks
Nirman