Wednesday 16 December 2015

Create your very own generic GetById method using LINQ Expression Trees

Working with LINQ Expression Trees is sometimes somewhat a tough challenge for C#-programmers, since they usually do not work with Expression trees directly. But LINQ Expression Trees makes it possible to create highly dynamic functions and supports generics quite nicely. Let's create our very own generic GetById method using Linq Expression trees! First off, let's define a simple POCO and use the System.ComponentModel.DataAnnotations.KeyAttribute:

using System.ComponentModel.DataAnnotations;

namespace GetByIdLinqExpression
{
   
    public class ChoccieBar
    {

        [KeyAttribute]
        public int ItemStockId { get; set; }

        public string Title { get; set; }

        public int Qty { get; set; }

        public decimal ItemPrice { get; set; }


    }
}

Okay, let's then define our generic GetById method that will support LINQ expression trees:

using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System;
using System.Collections.Generic;
using System.Linq; 

namespace GetByIdLinqExpression
{
   
    public static class LinqExtensions
    {

        public static TEntity GetById<TEntity>(this IEnumerable<TEntity> source, object primaryKey)
        {
            var itemFound = source.AsQueryable().SingleOrDefault<TEntity>(GetByKeyExpression<TEntity>(primaryKey));
            return itemFound;
        }

        private static Expression<Func<TEntity, bool>> GetByKeyExpression<TEntity>(object primaryKey)
        {
            var primaryKeyProperty = typeof(TEntity).GetProperties()
                .First(p => p.GetCustomAttributes(typeof(KeyAttribute), false).Count() > 0); 

            //Create entity => portion of lambda expression 
            ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "element");

            //Create entity.Id portion of lambda expression 
            MemberExpression property = Expression.Property(parameter, primaryKeyProperty.Name);

            //Create 'id' portion of lambda expression 
            var equalsTo = Expression.Constant(primaryKey);

            //Create entity.Id == 'id' portion of lambda expression 
            var equality = Expression.Equal(property, equalsTo);

            //finally create the entire expression: entity => entity.Id = 'id' 
            Expression<Func<TEntity, bool>> retVal = Expression.Lambda<Func<TEntity, bool>>(equality,
                new[] { parameter });

            return retVal;
        }

    }

}

Note that in our customized extension method we will first take the IEnumerable collection and use the AsQueryable method, since we will use Linq Expression trees. Next we have our own private method that builds up the necessary lambda expression using parameterexpression, memberexpression, constantexpression and equal or equality expression before finally handing it over to a lambdaexpression. If you find it hard to follow, note that you will get nice tooltips as you debug the method. Learning how to assemble for example lambda expressions in Linq expression trees is a must. And yes, the code can quickly grow. The key point is that once you first got it right, you can unlock the complexity using simple calls such as GetById shown in the unit tests next. And of course other, more complex queries can be built up by simpler ones such as this. And let's then create some unit tests to test out this little baby:



    [TestClass]
    public class UnitTest1
    {
       
        [TestMethod]
        public void GetByIdDoesNotThrow()
        {
            var choccieBars = new List
            {
                new ChoccieBar { ItemStockId = 1, Qty = 5200, Title = "Marsbar", ItemPrice = 2.0M },
                new ChoccieBar { ItemStockId = 2, Qty = 5200, Title = "Milky Way", ItemPrice = 1.75M },
                new ChoccieBar { ItemStockId = 3, Qty = 5200, Title = "Bounty", ItemPrice = 2.25M },
                new ChoccieBar { ItemStockId = 4, Qty = 5200, Title = "Lion", ItemPrice = 1.75M }
            };

            var choccieFound = choccieBars.GetById(4);
            Assert.IsNotNull(choccieFound); 

        }

    }

And the test passes. Happy LINQ Expression coding! Remember that using Linq Expression trees there is a lot of things you can achieve in C#! Only creativity can stop you from what extension methods using linq expression trees can be made! And Linq Expression trees might seem difficult, but get started coding them and you soon will find out that they are fun to work with!
Share this article on LinkedIn.

No comments:

Post a Comment