Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamics Or Filter support #120

Open
VasylZvarydchuk opened this issue Dec 27, 2023 · 3 comments
Open

Dynamics Or Filter support #120

VasylZvarydchuk opened this issue Dec 27, 2023 · 3 comments

Comments

@VasylZvarydchuk
Copy link

VasylZvarydchuk commented Dec 27, 2023

Hi, my OData service doesn't support In statement and I need to make code like that:

var emails = new[] {"[email protected]", "[email protected]"}

 var builder = ODataQueryBuilder(baseUrl).For<MyEntity>(nameof(MyEntity)).ByList()

for(email in emails) {
   builder.Filter(t => t.Email== email)
}

but this code will generate Url like tha

baseUrl/MyEntity?$filter=Email eq '[email protected]' and Email eq '[email protected]'

How can I get the filter dynamically with OR statement instead of AND? I would like to have code like that

for(email in emails) {
   builder.OrFilter(t => t.Email== email)
}

that will generate this url

baseUrl/MyEntity?$filter=Email eq '[email protected]' or Email eq '[email protected]'

Is it possible to add such support? Thanks

@LinusCenterstrom
Copy link

While not explicitly supported this is still doable by dynamically creating the expression.

Here is an example in the form of a test using the TestClasses in this library

var validValues = new List<string>
{
    "44",
    "45"
};

var entityType = typeof(ODataTypeEntity);
var filterParameter = Expression.Parameter(entityType, "s");

var expr = validValues
    .Select(v => Expression.Equal(
        Expression.Property(filterParameter, nameof(ODataTypeEntity.TypeCode)),
        Expression.Constant(v)))
    .Aggregate(Expression.OrElse);

var filter = Expression.Lambda<Func<ODataTypeEntity, bool>>(expr, filterParameter);

var uri = _odataQueryBuilderDefault
    .For<ODataTypeEntity>(s => s.ODataType)
    .ByList()
    .Filter(filter)
    .ToUri();

uri.Should().Be("http://mock/odata/ODataType?$filter=TypeCode eq '44' or TypeCode eq '45'");

There are also other ways to construct the expression, for example by having a list of expressions and merging them. You might want to take a look at that to see if there is another way you prefer.

@VasylZvarydchuk
Copy link
Author

LinusCenterstrom

Thank you very much for the suggestion. That's exactly how did I solve it for now:


    public static Expression<Func<TEntity, bool>> GetOrFilter<TEntity>(string[] items, string parameterName)
    {
        ParameterExpression parameter = Expression.Parameter(typeof(TEntity), "t");
        var filterProperty = typeof(TEntity).GetProperty(parameterName);

        Expression body = Expression.Equal(
            Expression.Property(parameter, filterProperty),
            Expression.Constant(Uri.EscapeDataString(items[0])));

        for (var i = 1; i < items.Length; i++)
        {
            // Create an expression for (t.<parameterName> == item[i])
            var equalsExpression = Expression.Equal(
                Expression.Property(parameter, filterProperty),
                Expression.Constant(Uri.EscapeDataString(items[i])));

            body = Expression.OrElse(body, equalsExpression);
        }

        Expression<Func<TEntity, bool>> filter = Expression.Lambda<Func<TEntity, bool>>(body, parameter);

        return filter;
    }

But I'd like to have such code in Framework itself and also if I want a more complex scenario like that

http://mock/odata/ODataType?$filter=(TypeCode eq '44' and Param2 eq '1') or (TypeCode eq '45' and Param2 eq '2')

In that case such expression will become more complex and easier to use by old school method with string manipulations.

@LinusCenterstrom
Copy link

But I'd like to have such code in Framework itself and also if I want a more complex scenario like that

http://mock/odata/ODataType?$filter=(TypeCode eq '44' and Param2 eq '1') or (TypeCode eq '45' and Param2 eq '2')

In that case such expression will become more complex and easier to use by old school method with string manipulations.

Agreed, it can get confusing quickly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants