You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Some issues mentioned "support" of the OData (like this or this), but the real app doesn't work.
The problem is extended properties and injection made into the LINQ by ABP.
Image code like this (using DBContext just for simplicity):
public class UsersController : ODataController
{
private readonly MyDbContext _dbContext;
private readonly IObjectMapper _mapper;
private readonly ODataConventionModelBuilder _builder;
public UsersController(MyDbContext dbContext, IObjectMapper mapper)
{
_dbContext = dbContext;
_mapper = mapper;
_builder = new ODataConventionModelBuilder();
_builder.EntityType<IdentityUser>()
.HasName("IdentityUser")
.HasKey(t => t.Id);
_builder.EntityType<IdentityRole>()
.HasName("IdentityRole")
.HasKey(t => t.Id);
_builder.EntitySet<IdentityUser>("Users");
_builder.EntitySet<IdentityUser>("Roles");
}
public IQueryable<IdentityUserDto> Get(ODataQueryOptions<IdentityUserDto> query)
{
var model = _builder.GetEdmModel();
IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Users");
ODataPath path = new ODataPath(new EntitySetSegment(entitySet));
var enttyOpts = new ODataQueryContext(model, typeof(IdentityUser), path);
var opts = new ODataQueryOptions<IdentityUser>(enttyOpts, query.Request);
var queryable = (IQueryable<IdentityUser>)opts.ApplyTo(_dbContext.Users.AsQueryable<IdentityUser>());
var result = queryable.ToList();
return _mapper.Map<List<IdentityUser> ,List<IdentityUserDto>>(result).AsQueryable();
}
}
That will work and you even can do a very simple query like $filter=name eq 'John'. But as soon as you want to use any "extended" (from ABP point of view) properties like UserName (I have no idea why it counts it as Extended, to be honest) you will get error like this:
The LINQ expression 'DbSet()\r\n .Where(i => __ef_filter__p_0 || !(EF.Property(i, "IsDeleted")) && __ef_filter__p_1 || (Guid?)EF.Property(i, "TenantId") == __ef_filter__CurrentTenantId_2)\r\n .Where(i => (string)i.ExtraProperties.ContainsKey("UserName") ? i.ExtraProperties["UserName"] : null == __TypedProperty_0)' could not be translated. Additional information: Translation of method 'System.Collections.Generic.Dictionary<string, object>.ContainsKey' failed. If this method can be mapped to your custom function, see https://go.microsoft.com/fwlink/?linkid=2132413 for more information. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.g__CheckTranslated|15_0(ShapedQueryExpression translated, <>c__DisplayClass15_0& )
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_01.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable1.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)
at CommunityManager.OData.UsersController.Get(ODataQueryOptions`1 query)
at lambda_method2483(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.SyncObjectResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
The text was updated successfully, but these errors were encountered:
After a lot of digging, I can definitely say that OData support in ABP is not possible because of Extra Property feature. There is no support for this in AutoMapper and in OData library itself. You can build OData for your own entities, but not for OOB.
Issue:
ABP Framework >= 6.0
Some issues mentioned "support" of the OData (like this or this), but the real app doesn't work.
The problem is extended properties and injection made into the LINQ by ABP.
Image code like this (using DBContext just for simplicity):
That will work and you even can do a very simple query like $filter=name eq 'John'. But as soon as you want to use any "extended" (from ABP point of view) properties like UserName (I have no idea why it counts it as Extended, to be honest) you will get error like this:
The text was updated successfully, but these errors were encountered: