A Fluent API for defining queries. Allows fluent language based linq queries, and easy definition and consumption of Query Objects.
It all starts with the Query class. to begin a new query, just do the following:
Query<Book>
Then you select what you want to query against. If it's the entity itself, then you can use Is
, if it's a property you can use Has(b => b.SomeProperty)
and use a lambda expression to select the property. Finally select the predicate to resolve the query. For example:
Query<Book>.Is.EqualTo(otherBook);
Query<Book>.Has(b => b.Author).NotEqualTo("Oscar Wilde");
Query<Book>.Has(b => b.Title).Containing("The");
Query<Book>.Has(b => b.Available).False();
Query<Book>.Has(b => b.Pages).GreaterThan(1000);
Obviously, a large amount of the time, we want to query more than one thing. You can chain queries together using And
or Or
:
Query<Book>.Is.EqualTo(otherBook).Or.Has(b => b.Author).NotEqualTo("Oscar Wilde");
Query<Book>.Has(b => b.Pages).GreaterThan(500).And.Has(b => b.Available).True();
Once you've defined your query you can compile to an Expression:
Query<Book>.Has(b.Title).EqualTo("The Picture of Dorian Gray").AsExpression();
Context.Books.Where(Query<Book>.Has(b.Title).EqualTo("The Picture of Dorian Gray").AsExpression()).ToList();
You can also check if any object satisfies a query, either by using the IsSatisfiedBy
or the extension method Satisfies
on an object.
var query = Query<Book>.Has(b.Title).StartingWith("The");
query.IsSatisfiedBy(aBook);
anotherBook.Satisfies(query);
The idea of FluentQueries is to help the readability of LINQ queries. One way to do this is to utilise the FluentQueries framework to create classes that represent queries:
public class AuthorHasName : Query<Book>
{
public AuthorHasName(string firstName, string lastName)
{
Define(
Has(b => b.Author)
.EqualTo($"{firstName} {lastName}")
);
}
}
You now have a nice, explicit and reusable class for querying the authors name:
aBook.Satisfies(new AuthorHasName("Charles", "Dickens"));
Finally you can combine existing queries with new ones:
Query<Book>.Has(b => b.Pages).GreaterThan(1000).And.Is.Satisfying(new AuthorHasName("William", "Shakespeare"));
Or combine lambda expressions with queries:
Query<Book>.Has(b => b.Title).EndingWith("Wild").And.Has(b => b.Pages).Satisfying(p => p > 1000);
This means if there is anything not supported by FluentQueries you can still use a lambda expression combined with Queries.