Entity class for example:
```C#
public class DeviceEntity
{
[Key]
[MaxLength(100)]
public string Id { get; set; }
public ICollection<DeviceTagEntity> Tags { get; set; }
}
public class DeviceTagEntity
{
[MaxLength(100)]
[Required]
public string DeviceId { get; set; }
private DeviceEntity _Device;
public DeviceEntity Device { get => _Device; set { _Device = value; DeviceId = value?.Id ?? string.Empty; } }
[Required]
public string Tag { get; set; }
}
And there is a Model
```C#
public class Device
{
public string Id { get; set; }
public IEnumerable<string> Tags { get; set; }
}
The model used to return to OData queryable.
```C#
[HttpGet]
[EnableQuery]
public IQueryable
{
return dataContext.Devices.AsNoTracking().
Select(t => new Device
{
Id = t.Id,
Tags = t.Tags.Select(x => x.Tag)
});
}
### Further technical details
The problom cased when I use Where Tags.Any in odata client.
```C#
dataServiceContext.CreateQuery<Device>().Where(t => t.Tags.Any(x => x == "something")).ToArrayAsync();
public static async Task<T[]> ToArrayAsync<T>(this IQueryable<T> source)
{
if (source is DataServiceQuery<T> query)
{
return (await query.ExecuteAsync()).ToArray();
}
throw new NotSupportedException("This is not a odata server query.");
}
It will throw the exception on server side:
An unhandled exception was thrown by the application.
System.InvalidOperationException: The LINQ expression 'DbSet<DeviceEntity>
.Where(d => (Nullable<bool>)(d.AppId == __TypedProperty_0) && DbSet<DeviceTagEntity>
.Where(d0 => EF.Property<string>(d, "Id") != null && EF.Property<string>(d, "Id") == EF.Property<string>(d0, "DeviceId"))
.Select(d0 => d0.Tag) == null ? null : (Nullable<bool>)DbSet<DeviceTagEntity>
.Where(d1 => EF.Property<string>(d, "Id") != null && EF.Property<string>(d, "Id") == EF.Property<string>(d1, "DeviceId"))
.Any(d1 => d1.Tag== __TypedProperty_1) == (Nullable<bool>)True)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.<VisitMethodCall>g__CheckTranslated|8_0(ShapedQueryExpression translated, <>c__DisplayClass8_0& )
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetAsyncEnumerator(CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Infrastructure.AsyncEnumerableReader.ReadInternal[T](Object value)
at Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, Object asyncEnumerable, Func`2 reader)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
EF Core version: 3.1.3
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET Core 3.1
Operating system: Docker
IDE: Visual Studio 2019 16.6
@Kation Please post your OnModelCreating code--my guess is that public DeviceEntity Device { get => _Device; set { _Device = value; DeviceId = value?.Id ?? string.Empty; } } is not mapped.
@ajcvickers oh, sorry, I forgot paste map code.
There is a type configuration class only.
public class DeviceTagEntityMap : IEntityTypeConfiguration<DeviceTagEntity>
{
public void Configure(EntityTypeBuilder<DeviceTagEntity> builder)
{
builder.HasKey(t => new { t.DeviceId, t.Tag });
}
}
EF core will map all entities correctly.
ODATA added additional null check, so Where predicate is actually,
t.Tags.Select(x => x.Tag) == null ? null : t.Tags.Select(x => x.Tag).Any(x => x. == "something")
which we cannot translate. We don't know how to convert a null check on IEnumerable<Tag>
@smitpatel Thanks, I'll going to find what can I do with OData.
This problem solving by add property to OData's EnableQueryAttribute to disable null propagation.
[EnableQuery(HandleNullPropagation = HandleNullPropagationOption.False)]