Dynamic EF operations with EF.Property

Using EF.Property to dynamically reference entity properties using a string

Home DailyDrop

Daily Knowledge Drop

The EF.Property static method can be used to reference an entity property dynamically using a string representation of the property name. This can be leveraged to perform dynamic ordering or filtering on the DbSet, for example.


Usage

In all of the examples below, a simple Blog table is being used which contains a list of 10 000 blog records.


Selection

Suppose we wanted to get a list of all Blog Titles - a simple enough query using Entity Framework:

var titles = context.Blogs
    .Select(e => e.Title)
    .ToList();

Suppose now we have a requirement to allow the user to choose which specific column data should be returned. This could be done with a switch statement or multiple if statements, but this is not a sustainable approach. The better option is to use Ef.Property - this allows for the column name to be specified as a string:

var dynTitle = context.Blogs
    .Select(e => EF.Property<string>(e, "Title"))
    .ToList();

Here we get all Titles, without ever referencing the Title property on the Blog entity directly.

This can be enhanced, and a generic method created to select values from the specified table and column:

// get all ids from the Blog table
var ids = GetColumnValues<Blog, int>("Id");
Console.WriteLine($"Num Ids in list: {ids.Count}");
Console.WriteLine($"First Id in list: {ids.First()}");

// the entity type and the colum value type are specific
// as well as the column name
public List<TColumn> GetColumnValues<TEntity, TColumn>(
    string columnName) where TEntity : class
{
    using var context = new DemoContext();

    return context.Set<TEntity>()
        .Select(e => EF.Property<TColumn>(e, columnName))
        .ToList();
}

The output is as follows:

Num Ids in list: 10000
First Id in list: 1

We now have a dynamic method to retrieve all values from the specified column.

The EF.Property can be used anywhere a entity property would traditionally be used - this means it could also be used for dynamic ordering and filtering!


Ordering

We can use the above GetColumnValues method as a template for a new method to perform dynamic ordering on the Blog entity:

List<Blog> GetBlogs(string sortProperty, int pageSize)
{
    using var context = new DemoContext();

    // instead of specifying the column to order by 
    // directly, EF.Property is used
    return context.Blogs
        .OrderBy(e => EF.Property<object>(e, sortProperty))
        .Take(pageSize)
        .ToList();
}

This can now be invoked as follows:

// get 5 blogs sorted by Id
var sortedById = GetBlogs("Id", 5);
Console.WriteLine($"Sorted by Id, the first Id " +
    $"is: {sortedById.First().Id}");

// get 5 blogs sorted by Title
var sortedByTitle = GetBlogs("Title", 5);
Console.WriteLine($"Sorted by Title, the first Id " +
    $"is: {sortedByTitle.First().Id}");

The output:

Sorted by Id, the first Id is: 1
Sorted by Title, the first Id is: 665

Filtering

One final example of how EF.Property can be leveraged, is to perform dynamic filtering:

public List<Blog> GetFilterBlogs<T>(string sortProperty, T value, int pageSize)
{
    using var context = new DemoContext();

    return context.Blogs
        .Where(e => EF.Property<T>(e, sortProperty).Equals(value))
        .Take(pageSize)
        .ToList();
}

This allows for a column name and column value to be specified dynamically and have filtering applied:

// filter by id
var filteredById = GetFilterBlogs<int>("Id", 1011, 1);
Console.WriteLine($"Filtered count: {filteredById.Count}");

// filter by title
var filteredByTitle = GetFilterBlogs<string>("Title", 
    "Dynamic EF operations with EF.Property", 1);
Console.WriteLine($"Filtered count: {filteredByTitle.Count}");

Executing the above:

Filtered count: 1
Filtered count: 1

Notes

Ef.Property is a very useful utility method when required to change the target column of operations at runtime, such as when ordering or filtering dynamically (from a user interface grid, for example). There may be a performance impact in using this over referencing the column directly (but this should be benchmarked to confirm for the specific use case) - however these are the tradeoffs which need to be considered when deciding which method to use.


References

EF.Property(Object, String) Method

Daily Drop 154: 06-09-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net ef property