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

$expand will override EFCore Include() method when it is requested in the odata queries #1305

Open
mehdi-vendoroo opened this issue Aug 29, 2024 · 5 comments
Assignees

Comments

@mehdi-vendoroo
Copy link

mehdi-vendoroo commented Aug 29, 2024

I want to set a default limit to one of the collection properties on an entity.

public class Job
{
    public int Id {get; set;}
    public ICollection<Address> Addresses {get; set;}
}

Thus I limited the collection by the EFCore Include method like this:

public IQueryable<Job> GetLimitedAddressJobQuery()
{
   return DbContext.Jobs.Include(j => j.Addresses.Where(a => a.Type == AddressTypes.Public));
}

But the odata result shows that, the limit I set for Addresses completely overriden when $expand requested in the query and it will completely ignores it.

Normally I can set default limits on the odata requested query by just simply apply some LINQs on the IQueryable that I want to return from the get action method in the controller to pass to EnableQuery attribute. but I see a different behaviour in here. Is it a bug? or the default behaviour should be considered different when applied LINQ queries to collections is wanted?
If it is the default, what will be a workaround for setting a default limit to collection properties when $expand requested?

@mehdi-vendoroo mehdi-vendoroo changed the title $expand will override EFCore Include() method when it is requested in queries $expand will override EFCore Include() method when it is requested in the odata queries Aug 29, 2024
@julealgon
Copy link
Contributor

@mehdi-vendoroo have you considered setting that limitation as a global filter?

You should be able to constrain addresses to just return public ones with that mechanism.

That, of course, assumes this is a global constraint you want to enforce.

@mehdi-vendoroo
Copy link
Author

mehdi-vendoroo commented Aug 29, 2024

@mehdi-vendoroo have you considered setting that limitation as a global filter?

You should be able to constrain addresses to just return public ones with that mechanism.

That, of course, assumes this is a global constraint you want to enforce.

Nope, it is a special use case. I don't want to apply it to every queries that the mentioned collection is involved in.

@julealgon
Copy link
Contributor

@mehdi-vendoroo

Nope, it is a special use case. I don't want to apply it to every queries that the mentioned collection is involved in.

Fair enough.

You might still be able to leverage global filters by providing a parameter to the DbContext that you use inside of the query filter to conditionally run the restriction. This would allow you to restrict access only at specific places or requests in your codebase.

@mehdi-vendoroo
Copy link
Author

mehdi-vendoroo commented Aug 30, 2024

@mehdi-vendoroo

Nope, it is a special use case. I don't want to apply it to every queries that the mentioned collection is involved in.

Fair enough.

You might still be able to leverage global filters by providing a parameter to the DbContext that you use inside of the query filter to conditionally run the restriction. This would allow you to restrict access only at specific places or requests in your codebase.

Yeah that could resolve the problem. But It will be a really mess to drag this down to data and infrastructure layers of the application in the terms of the architecture and soc point of view.

Is there any workaround that I can fix this in the way of ODataish things? All I need is to replace or attach a filter for an entity in the query before execution. So far I tried to hack IFilterBinder and replace the filter expression by a new one, like Expression<Func<Address,bool>>. But it wasn't successful and I got an exception stated "Boolean operator does not support Expression<Func<Address,bool>> for singleValued filters".

Is there any services to custom implement, mock or overriding something to hook up to it for this purpose?

@julealgon
Copy link
Contributor

@mehdi-vendoroo

Yeah that could resolve the problem. But It will be a really mess to drag this down to data and infrastructure layers of the application in the terms of the architecture and soc point of view.

Oh, I mostly agree with you. Sorry if it came out the wrong way, but I wasn't implying the global filter on EF was necessarily a great solution to this, but more of a workaround.

I'm also curious to know whether there is a simple way to achieve what you need here using a "higher level" approach.

The only other thing I'll comment though is in regard to robustness. OData allows the caller to "navigate" pretty much your entire DB structure, so they could potentially "reach" your address model from several different places/endpoints. If you wanted to include a filter like you did there, then you'd need to make sure it was included in every single place where addresses were accessible. In that sense, maybe the global filter approach is not that much of a workaround and maybe an actual robust solution, as it ensures the entity will be filtered no matter how the client reaches it in a query. Just keep that in mind.

Hopefully someone on the team will chime in here.

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

No branches or pull requests

3 participants