Clean up your LINQ with Load Expressions

Often times in an application, you will need data from across several tables. One approach to get all this data at once is to use the LINQ .Include() function, which will pull in all the data of the specified parent or child table. However, this can often be too heavy, as you may not need every column so you end up pulling more data from the database than is required. When this is the case, the best practice is to use a Data Transfer Object or DTO which is one flat object that combines properties from parents and children.

Below, I demonstrate a simple use of a DTO, using .Include()


var products = Uow.Context.Products.Include(x => x.ParentTable).Include(x => x.ChildTable).ToList();

var dtoList = new List<ProductDto>();
foreach(var product in products)
{
var dto = new ProductDto{
// Copy over properties
...
// Copy over parent properties
...
// Copy over child properties
...
};
dtoList.Add(dto);

}


As I mentioned before, this is not an ideal solution. Not only am I pulling too much data in, but I also need to loop through the items again to turn them into DTOs.

LINQ Select


The more efficient solution is to use LINQ's .Select() method. One note about this method is that if you are using LINQ to entities, you cannot use methods inside the statement, as they will be unable to translate to SQL, yet they will compile and you will see the error at runtime.

Below performs the same function as the above example, but only pulls the needed data from the DB.

var dtoList = Uow.Context.Products.Select(x =>
new ProductDto{
// Copy over properties
// x.Property
// Copy over parent properties
// x.Parent.Property
// Copy over child properties
// x.Child.Property
}.ToList();

Inside of the Select statement, you will have access to all properties from the start table (Products, in this case name x).

Clean LINQ Select

The above solution is great, but if you are coping a lot of properties inside the Select or are reusing this DTO in other places, your code could become difficult to read. You can create an Expression so you only have to define this property copy one time.

This code will go inside your DTO class

public static Expression<Func<Product, ProductDto>> Load = x => 
new ProductDto{
// Copy over properties
// x.Property
// Copy over parent properties
// x.Parent.Property
// Copy over child properties
// x.Child.Property
};

To use it, your LINQ query would be the following:

var dtoList = Uow.Context.Products.Select(ProductDto.Load).ToList();

All of a sudden, many lines of code have turned into just one! This strategy even works for LINQ joins, you will just need to add an extra parameter to the Func in the Load method.

Thanks for reading!

Comments

Popular posts from this blog

ASP.NET Identity Remember Me

IIS Express Client Certificates

ASP.NET MVC - How to enable/disable CaC/Client Certificate authentication per area or route.