ZEXSM / OData.QueryBuilder

OData.QueryBuilder - library for creating complex OData queries (OData version 4.01) based on data models with linq syntax.
MIT License
71 stars 31 forks source link

Consequent ODataQueryCollection same methods calls leads to strange output #84

Closed Pisaren closed 2 years ago

Pisaren commented 2 years ago

If I call Filter() method twice then I get two same parameters in Uri after ToUri() method call, like "docs?$filter=a eq 1&$filter=b eq 7". In such case ToDictionary() method returns an error after trying to add same key to dictionary.

ZEXSM commented 2 years ago

Give an example in the format expectation is reality

Pisaren commented 2 years ago

When I execute next code

var builder = new ODataQueryBuilder().For<Model>("docs")
    .ByList()
    .Filter(x => x.Id == 1)
    .Filter(x => x.Type == 7);
var uri = builder.ToUri();
var dict = builder.ToDictionary();

The uri variable get value "docs?$filter=Id eq 1&$filter=Type eq 7" with two "$filter" query parameters, but expect "docs?$filter=Id eq 1 and Type eq 7". When I call ToDictionary() method I get - System.ArgumentException: An item with the same key has already been added. Key: $filter

ZEXSM commented 2 years ago

As far as I know and tested, a query with two filters at the same level will not work.

  1. This is not reflected in the specification.
  2. The request fails.

If this query is built without an OData.QueryBuilder, does it get executed?

ZEXSM commented 2 years ago

Hi. I propose to combine n-filters on one level into one through the operator and

var builder = new ODataQueryBuilder().For("docs") .ByList() .Filter(x => x.Id == 1) .Filter(x => x.Type == 7); var uri = builder.ToUri(); var dict = builder.ToDictionary();

actual docs?$filter=Id eq 1&$filter=Type eq 7 expected docs?$filter=Id eq 1 and Type eq 7

michaelgr1 commented 2 years ago

I just stumbled upon the same problem. I think the idea of chaining filter calls and then combining them with 'and' is great. It would also make the following use case much more convenient. In my case, I get filter values from the UI and need to decide whether to include them in the query or not. If they are not empty/null and if they are marked as active, I include them. Adding the functionality you mentioned will allow something like that:

var builder = new ODataQueryBuilder().For("docs").ByList(); if (Name != null) { builder = builder.Filter(x => x.Name == Name); }

if (Label != null) { builder = builder.Filter(x => x.Label == Label); }

This is much better as opposed to having nested if statements. If there is already a way to achieve this behavior I would be happy to see an example. Thanks a lot, Michael.