OData / WebApi

OData Web API: A server library built upon ODataLib and WebApi
https://docs.microsoft.com/odata
Other
855 stars 473 forks source link

How to support $select on non-CLR types? #2338

Open PatrickHofman opened 4 years ago

PatrickHofman commented 4 years ago

We have a dynamic data model which we expose using OData. The EDM model is constructed as type-less model. We want to support $select and other options.

Assemblies affected

OData Web API 7.4.1.

Reproduce steps

A sample repository is in https://github.com/PatrickHofman/odata-web-api-issue-2338/.

Most interesting part is in https://github.com/PatrickHofman/odata-web-api-issue-2338/blob/main/WebApplication8/WebApplication8/Controllers/OData4Controller.cs:

https://github.com/PatrickHofman/odata-web-api-issue-2338/blob/afb76a8c0057bccf209a48b129e50eba3a1c7987/WebApplication8/WebApplication8/Controllers/OData4Controller.cs#L52-L83

Expected result

We do some pre-processing on the filters to make sure we don't fetch too much from the internal data store. I would love the second code part to work too so OData can automatically correct what we were not able to do yet, like some missing filters and select/expand.

Actual result

An exception is raise:

NotSupportedException: The query option is not bound to any CLR type. 'ApplyTo' is only supported with a query option bound to a CLR type.

Additional detail

I know this is not supported yet. I would love to hear what we can do to implement this ourselves when it is not feasible to implement in the general package.

habbes commented 4 years ago

@PatrickHofman would generating CLR types dynamically be an option you would consider? I think WebAPI currently has some issues when it comes to support of types in dynamic assemblies, but that could be fixed. I'm wondering whether generating CLR types dynamically, then an EDM model based on those types would allow you to achieve what you're aiming at.

PatrickHofman commented 4 years ago

That is an interesting idea. So you basically say: generate the CLR types in memory, then you should be able to use IQueryable and ApplyTo just as you normally would (although through reflection or so)?

habbes commented 4 years ago

@PatrickHofman I think that would be a workaround worth trying out.

Are you generating the model once during some bootstrapping process of your service, or are you generating the model on each request? One of the challenges of dealing with dynamically generated CLR types is unloading them once you no longer need them. But if this is not an issue with your use-case, then I believe this approach could work well. Give it a try and let us know if you face any issues.

PatrickHofman commented 4 years ago

@habbes The model differs per user and per 'segment' chosen. The model is 100% dynamic. I am generating the model once based the user ID and segment. Unloading is an issue indeed, which I am not sure how bad it will turn out. I will make a test and see if it is feasible.

Any thoughts on if it is feasible to write an IQueryable on IEdmEntityObject?

PatrickHofman commented 4 years ago

Just to give an idea why the data model differs: actually we are proxying about 70+ online and offline data sources, which can also be combined in one segment, and for some of them, the data model differs per user per data source.

habbes commented 4 years ago

@PatrickHofman I believe you can create an IQueryable on IEdmEntityObject the way you did it. But the problem is that it's not supported by queryOptions.ApplyTo, which is the main issue you're facing.

PatrickHofman commented 4 years ago

@habbes You are right on that. Have you have any insight on the complexity of implementing that?

habbes commented 4 years ago

@PatrickHofman OData WebAPI does have support for untyped or non-CLR objects, but there's a feature gap when it comes to the support of query options. At the moment I don't believe that there's a clear path on how to solve this gap. I believe the issue is related to generating the appropriate LINQ expressions when dealing with untyped objects. @xuzhg could you provide more insight on this issue?

lhigueros commented 1 year ago

Is this going to be supported anytime soon? My use case is one where I am using reflected types from datatables and even though the data classes have standard CLR types in them, they are not being treated as static classes. Is there a workaround? thank you