FormattableStringFactory - Creating dynamic FormattableString instances

8/19/2024
2 minute read

I recently came across the FormattableStringFactory to create dynamic FormattableString instances. This is a very useful feature in combination with safe SQL queries and the SqlQuery method of Entity Framework Core.

SqlQuery method

Short recap: The SqlQuery method of Entity Framework Core allows you to execute raw SQL queries and map the results to entities. This is useful if you want to execute complex queries that are not possible with LINQ.

var ids = await context.Database
    .SqlQuery<int>($"SELECT [BlogId] FROM [Blogs]")
    .ToListAsync();

It wants a FormattableString as input so it can safely interpolate the values into the SQL query and prevent SQL injection attacks. The "problem" is that you can't concatenate FormattableString instances directly. I needed this for a dynamic SQL query. Imagine in the given example above sometimes you want to filter for specific ID's from a given list.

var ids = GetIds();
// If ids is empty, the SQL query isn't valid
var query = $"SELECT [BlogId] FROM [Blogs] WHERE [BlogId] IN ({string.Join(", ", ids)})";

FormattableStringFactory

But we can utilize the FormattableStringFactory to create dynamic FormattableString instances from a given string!

var ids = GetIds();

var stringBuilder = new StringBuilder("SELECT [BlogId] FROM [Blogs]");
if (ids.Any())
{
    stringBuilder.Append(" WHERE [BlogId] IN ({0})", string.Join(", ", ids));
}

var query = FormattableStringFactory.Create(stringBuilder.ToString());
var result = await context.Database
    .SqlQuery<int>(query)
    .ToListAsync();

If your FormattableString contains placeholders, you can pass them in like this:

var query = "Hello {0}!";
var formattableString = FormattableStringFactory.Create(query, "World");

These two mechanisms combined allow you to create dynamic SQL queries with Entity Framework Core in a safe way.

An error has occurred. This application may no longer respond until reloaded. Reload x