Giter Site home page Giter Site logo

zhaytam / dynamicexpressions Goto Github PK

View Code? Open in Web Editor NEW
50.0 4.0 11.0 36 KB

A dynamic expression builder that can be used to dynamically sort and/or filter LINQ/EF queries

Home Page: https://blog.zhaytam.com/2020/05/17/dynamic-sorting-filtering-csharp/

License: MIT License

C# 100.00%
expression-trees sorting filtering netstandard

dynamicexpressions's Introduction

DynamicExpressions

A dynamic expression builder that can be used to dynamically sort and/or filter LINQ/EF queries.
I wrote a blog post that explains the usage & benefits, check it out here.

This library tries to generate Expression Trees as close to the one generated by c# as possible, so in almost all cases, you don't even need to worry about performance.

Badges
NuGet NuGet Nuget
License GitHub

Property Getters

This is usually used when you want to do an OrderBy or OrderByDescending.
For example:

_dbContext.Products.AsQueryable().OrderBy(p => p.Price);

If you want to give the ability for the user to choose what to order by, you'll need to do a switch statement with all the possible values, which can be exhausting, especially if it's for multiple entities.

Using this library, you can simply do this:

var propertyGetter = DynamicExpressions.GetPropertyGetter<Product>(propertySentByUser);
// ^ can be cached or even compiled to a Func<Product, object>
var query = _dbContext.Products.AsQueryable().OrderBy(propertyGetter);
// Or OrderByDesceding

And it will handle all the properties, unless you do a pre-validation.

Predicates

Simple

Predicates in c# are functions that take one or more parameter and returns a boolean.
For example, when you want to filter an IQueryable, you use a Func<TEntity, bool>.

For example:

_dbContext.Products.AsQueryable().Where(p => p.Name.Contains(termSentByUser));

Again, this only handles a Contains filter on the Name property.
The more properties and operators you have, the more "boring" code you'll need to write.

Using this library, you can simple do this:

var predicate = DynamicExpressions.GetPredicate<Product>(propertySentByUser, operatorSentByUser, valueSentByUser);
// ^ can also be cached or compiled and used anywhere
var products = _dbContext.Products.AsQueryable().Where(predicate).ToList();
// ^ or FirstByDefault, Any, etc...

Advanced

In the previous example, we filtered products only on their price. We will now see how we can create advnaced dynamic predicates.

Let's say for example you want to create the following filter:

Product.Enabled
&& (Product.Brand == "Nike" || Product.Brand == "Adidas")
&& (Product.Price >= 20 && Product.Price <= 100)

Using this library, you're able to do this:

var predicate = new DynamicFilterBuilder<Product>()
  .And("Enabled", FilterOperator.Equals, true)
  .And(b => b.And("Brand", FilterOperator.Equals, "Nike").Or("Brand", FilterOperator.Equals, "Adidas"))
  .And(b => b.And("Price", FilterOperator.GreaterThanOrEqual, 20).And("Price", FilterOperator.LessThanOrEqual, 100))
  .Build();
  
var products = _dbContext.Products.AsQueryable().Where(predicate).ToList();

Of course, everything can be configurable and provided by the user.
A more real life example would be for the frontend (user) to give you a list of filters that you can dynamically apply using a DynamicFilterBuilder.

Feedback

If you find a bug or you want to see a functionality in this library, feel free to open an issue in the repository!
Of course, PRs are very welcome.

dynamicexpressions's People

Contributors

alexgritton avatar dnyaneshwar-surywanshi avatar zhaytam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

dynamicexpressions's Issues

Anyway to wrap this into a `Expression`

Hi, thanks for this package it's very useful. So the predicate returend is of type Func<> which is not suitable when trying to execute this in SQL server.

What i am trying to ask is if there is any way to create a Expression<Func<T, bool>> from this package? So I can call it on SQL server instead of evaluating client side.

Filtering is not working on Nullable properties

Steps to reproduce.

  1. Create a model that has a nullable property.
  2. Use the nullable property for filtering collection

Actual Result

System.InvalidOperationException : The binary operator Equal is not defined for the types 'System.Nullable`1[System.Int32]' and 'System.Int32'.

Stack Trace: 
Expression.GetEqualityComparisonOperator(ExpressionType binaryType, String opName, Expression left, Expression right, Boolean liftToNull)
Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
Expression.Equal(Expression left, Expression right)
DynamicExpressions.RobustEquals(MemberExpression prop, ConstantExpression constant) line 89
DynamicExpressions.CreateFilter(MemberExpression prop, FilterOperator op, ConstantExpression constant) line 62
DynamicExpressions.GetFilter(ParameterExpression param, String property, FilterOperator op, Object value) line 55
DynamicExpressions.GetPredicate[TEntity](String property, FilterOperator op, Object value) line 37
PredicateTests.GetPredicate_ShouldHandleNumericalOperators(Int32 id, String title, String property, FilterOperator op, Object value) line 22

How do i filter with comparison

I wanted to achieve this filter with using dynamicexpression

.Where(b => string.Compare(b.Title, nextProduct.Title, StringComparison.OrdinalIgnoreCase) > 0 || (b.Title == nextProduct.Title && b.Id > productFilter.NextProductId))

Please provide me code snippet if you have already.

Throws NullReferenceException when checking nested object

public class TodoItem
{
    public string name { get; set; }
    public TodoItem Child { get; set; }
}

var items = new List<TodoItem>(){
new TodoItem(){ name="2" }
}

var predicate = DynamicExpressions.DynamicExpressions.GetPredicate
<TodoItem>("Child.name", FilterOperator.Equals, "333");

var lst = items.AsQueryable().Where(predicate).ToList();

There is no way to bypass null references like "Child?.name"?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.