Writing pipes and filters for fluent OR-mapping
Tags: dotnet, entityframework, linq, designpatterns
Published: 2023-05-11 16:23:47

---
title: Writing pipes and filters for fluent OR-mapping
description: There's more to do than just writing LINQ expressions when using EF Core!
published: true
date: 2022-08-15 09:13:37 UTC
tags: dotnet, entityframework, linq, designpatterns
canonical_url: https://keepontruckin.hashnode.dev/fluent-or-mapping
cover_image: https://user-images.githubusercontent.com/958227/233758730-8cf36a84-c1f4-4be5-a3bc-90216e2f46dc.jpeg?auto=compress
---

I like the idea of [fluent interfaces](https://martinfowler.com/bliki/FluentInterface.html). It gives the whole thing a very _Ubiquitous_ feel since the code becomes more understandable, say, two months from now like [Uncle Bob says in the Clean Code](https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29).

```csharp
// An example LINQ expression to filter all active products
// that belongs to a specified supplier.
db.Products
  .Where(p => !p.Discontinued && p.SupplierId == supplierId)
  .Take(10)
  .ToList();
```

### Simplifying query expressions

The first thing we are going to need is a lot of [query expressions](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions#lambdas-with-the-standard-query-operators). I can [decompose or consolidate](https://sourcemaking.com/refactoring/simplifying-conditional-expressions) query expressions so a little [extract method](https://sourcemaking.com/refactoring/composing-methods) magic is all that is necessary to get started. Kids' stuff.

```csharp
// Better readability.
db.Products.Where(p => Active(p) && WithSupplier(p, supplierId));
// Better resuability.
db.Suppliers.Where(s => s.Products.Any(p => Active(p));
```

That seems a little better since it allows reusing the query expressions. [LINQ](https://docs.microsoft.com/en-us/dotnet/csharp/linq/linq-in-csharp) may look like the best thing that happened for .NET, but it's getting all kinds of help from our friends at C#. It's the [extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods).

### Chaining query expressions

The other thing we're going to need is chaining. And that means [extension methods](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods). It's slightly obnoxious that extension methods require <mark>non-nested non-generic static classes</mark>. So what does each predicate have that can be used for chaining that the fluent interface requires? `IQueryable`?

```csharp
// Use filters to create the pipes.
db.Products.Active().WithSupplier(supplierId)
  .Take(10)
  .ToList();
// Extension methods for `IQueryable<Product>`.
static class IQueryableOfProduct
{
    static IQueryable<Product> Active(this IQueryable<Product> query)
        => query.Where(p => !p.Discontinued);
    static IQueryable<Product> WithSupplier(
        this IQueryable<Product> query, int supplierId)
        => query.Where(p => p.SupplierId == supplierId)
}
```

I can pass in the `IQueryable<>` domain entity type as the first parameter on which the method must operate. All I have to do is add the `this` modifier to the parameter and the C# compiler will do the rest for me. I'm not going to lie, you'd be amazed how tricky it is and if you return the wrong type, chaining breaks and nothing gets compiled.

### Describing pipes and filters

Naming things is hard. But there are more problems. Not only are the extension methods should be reusable, but they must be understandable. And you do want the code to scream what kind of business there is. Using a [domain-specific language](https://martinfowler.com/bliki/DomainSpecificLanguage.html) to describe methods seems like the right answer. Indeed.

/KP