IharYakimush / comminity-data-odata-linq

Use OData filter text query in linq expresson for any IQuerable without ASP.NET dependency. Support netstandard2.0
Other
42 stars 16 forks source link

how works $filter in $expand ? #29

Closed ChristopherLenz closed 5 years ago

ChristopherLenz commented 5 years ago

Hello,

we use this project since some weeks. It workds great :thumbsup:

No we encountered one issue.

Given is following architecture

        class MyClassA
        {
            [Key]
            public string String { get; set; }

            public List<MyClassB> Subs { get; set; }
        }

        class MyClassB
        {
            [Key]
            public int Integer { get; set; }
        }

It looks like it is not possible to assign following odata:

$filter=String eq 'A'&expand=Subs($filter=Integer eq 1

Thanks in advance

IharYakimush commented 5 years ago

It should work, check https://github.com/IharYakimush/comminity-data-odata-linq/blob/develop/Community.Data.OData.Linq.xTests/ExpandTests.cs line 129.

What exception you got when trying this query ? How you apply this query (code sample is needed) ? What nuget package versions you use ?

ChristopherLenz commented 5 years ago

ahh okay I see. If I want to filter the "expands" I need to use the functions SelectExpand() or SelectExpandAsQueryable(). If I do this, I lose the generic type, which I have, while using Filter(), OrderBy() and so on. This means there is no other way?

        [TestMethod]
        public void SubLevelFilterTest()
        {
            var odataQuery = GetSampleData().OData();
            odataQuery = odataQuery.Filter("String eq 'A'");

            // This is what I used until now; good result
            var serializeCorrect = JsonConvert.SerializeObject(odataQuery);

            // this is what I have to do to make us of the expand-filter?
            IQueryable<ISelectExpandWrapper> collection = odataQuery.SelectExpandAsQueryable("Subs", "Subs($filter=Integer eq 1)");
            var serializeWrong = JsonConvert.SerializeObject(collection);
        }

        private static IQueryable<MyClassA> GetSampleData()
        {
            return new List<MyClassA>()
            {
                new MyClassA()
                {
                    String = "A",
                    Subs = new List<MyClassB>() {{new MyClassB() {Integer = 1}}, {new MyClassB() {Integer = 2}}, {new MyClassB() {Integer = 3}}, {new MyClassB() {Integer = 4}}}
                },
                new MyClassA()
                {
                    String = "B",
                    Subs = new List<MyClassB>() {{new MyClassB() {Integer = 1}}, {new MyClassB() {Integer = 2}}, {new MyClassB() {Integer = 3}}, {new MyClassB() {Integer = 4}}}
                }
            }.AsQueryable();
        }
IharYakimush commented 5 years ago

If you need only json representation, you can add package Community.OData.Linq.Json, so

IEnumerable<ISelectExpandWrapper> collection = GetSampleData().OData().Filter("String eq 'A'").SelectExpand("String", "Subs($filter=Integer eq 1)");            
            string result1 = collection.ToJson().ToString();

Using expand and saving generic type is not possible. If saving generic type is mandatory, you can try

MyClassA[] array = GetSampleData().OData().Filter("String eq 'A'").ToArray();
            foreach (MyClassA item in array)
            {
                item.Subs = item.Subs.AsQueryable().OData().Filter("Integer eq 1").ToList();
            }

            string result2 = JsonConvert.SerializeObject(array);

however I would not recommend second option, because in case of real data source it might lead to fetching a lot of data from it.

ChristopherLenz commented 5 years ago

Hi,

thanks. I gave it a try. but it takes forever.

I extended the test this way:

If I do following I get extreamly different execution-times

OData().SelectExpand(select, expand).ToJson().ToString()

Edit: If I remove the ToJson() it tooks less than 1 second

IharYakimush commented 5 years ago

ensure that you pre-load Subs (MyClassB) from data source instead of lazy loading

ChristopherLenz commented 5 years ago

This was without a datasource behind. This was a pre-generated list in a unit-test

IharYakimush commented 5 years ago

Hi @ChristopherLenz, I added unit tests for performance and not able to reproduce the issue. Please check commit above and verify that we are doing the same.

ChristopherLenz commented 5 years ago

Hi @ChristopherLenz, I added unit tests for performance and not able to reproduce the issue. Please check commit above and verify that we are doing the same.

Okay I have to admit that I forgot an important information... My benchmarks were executed multiple times. So with one iteration I get roughly 3000ms for SelectExpand() --> ToJson() with 2000 items. This is similar to your test.

Thanks for all the help, but this is too slow for my use case. If I find an performance-improvement I will let you know