OData / WebApi

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

odata .net core api db access is async or not? #1203

Closed suadev closed 6 years ago

suadev commented 6 years ago

Hi,

Actually this is a simple question, i check the source code out but could not find where odata hit the DB.

Is db access async? Just want to be sure about it. Thanks.

suadev commented 6 years ago

Any comment? @xuzhg @robward-ms

xuzhg commented 6 years ago

@suadev I don't think DB access is in the scope of OData. OData defines a set of practices for building your data model (using Entity Data model, EDM), describing your data model (using Common Schema Definition Language, CSDL) and consuming your data (using JSON/XML). It's developers' responsibility to retrieve/update database.
Maybe @robward-ms @mikepizzo has more inputs.

suadev commented 6 years ago

@xuzhg, when i checking the source code of odata, i saw a method that called "ExecuteQuery". Actually that method made me think like that. I hope @robward-ms or @mikepizzo or somebody else can give us some more info.

Thanks!

ysmoradi commented 6 years ago

Whenever you define odata actions or functions, you can return data either sync or async, it depends on your code, similar to web api. But in case you return IQueryable in your function/action which has EnableQuery attribute applied, it applies $filter, $order by etc, then it executes that IQueryable "sync" to produce response. This is because every IQueryable provider such as ef, ef core, raven db, mongo db IQueryable providers have their own async methods which odata is not aware of. But every IQueryable can be executed "sync" using foreach easily. Actually this is done at web api level, it's not a odata thing. OData's EnableQuery applies odata query and leaves IQueryable to web api. Note that when you pass $inlineCount, odata's EnableQuery executes query to get total count in a "sync" way. It's important to know that odata is a standard and it has nothing to say about being sync or async. We're talking about asp.net web api odata "defaults" here. You can configure that to make it async too.

robward-ms commented 6 years ago

@ysmoradi and @xuzhg are correct. @suadev - Can you close the issue if the question is answered?

bdebaere commented 3 years ago

@ysmoradi

It's important to know that odata is a standard and it has nothing to say about being sync or async. We're talking about asp.net web api odata "defaults" here. You can configure that to make it async too.

The way I interpret the first sentence and the last two sentences makes me believe they seem to conflict with eachother. It seems you are alluding to a possibility of configuring OData to be async. Can you clarify?

We want our API to scale well and not have all our threads blocked while waiting for IO, as such asynchronous IO is a necessity.

ysmoradi commented 3 years ago

OData as a library, has no dependency on | Entity Framework Core | Entity Framework | Hibernate | and other data access providers. When you return IQueryable, OData's EnableQuery action filter can use "ToArray" method which is defined in System.Linq (And we know ToArray is not async) Ef has its own ToArrayAsync, Ef Core has its own ToArrayAsync, NHibernate has its own ToArrayAsync etc.

Solution? OData can define abstraction and provide several extra nuget packages to implement that abstraction.

For example, I created IDataProvider abstraction with following methods:

interface IDataProvider T[] ToArrayAsync(IQueryable query) int GetCountAsync(IQueryable query) bool CanAccept(IQueryable query)

then I implemented that in several nuget packages

class EfCoreDataProvider : IDataProvider T[] ToArrayAsync(IQueryable query) => query.ToArrayAsync(); // this calls ToArrayAsync of MS.EntityFrameworkCore.dll int GetCountAsync(IQueryable query) => query.ToLongCountAsync(); bool CanAccept(IQueryable query) => query is EntityQueryable;

class EfDataProvider : IDataProvider T[] ToArrayAsync(IQueryable query) => query.ToArrayAsync(); // this calls ToArrayAsync of EntityFramework.dll int GetCountAsync(IQueryable query) => query.ToLongCountAsync(); bool CanAccept(IQueryable query) => query is DbQuery;

, ...

Then developer can install as many as nuget packages she wants, then she registers many IDataProvider via dependency injection.

EnableQuery injects IEnumerable and tries to findout which of them is suitable for action's result (IQueryable) and uses that IDataProvider to get data asynchronously using its ToArrayAsync

using this approach, bit enabled projects have async pipeline

https://github.com/bitfoundation/bitframework/blob/master/src/Server/Bit.Server.Data.EntityFramework/Implementations/EfDataProviderSpecificMethodsProvider.c

bdebaere commented 3 years ago

@ysmoradi Right, but you did this yourself. This is not something OData currently provides, correct?

ysmoradi commented 3 years ago

Yeah, you're right. I think when @xuzhg says "I don't think DB access is in the scope of OData", he means OData team is not going to handle these things in the box.

In my opinion, this issue should gets resolved by dotnet itself. Some abstraction like IAsyncEnumerable, but for ToArrayAsync, CountAsync and FirstOrDefaultAsync etc

Every linq provider should implement those abstractions.