zzzprojects / EntityFramework-Plus

Entity Framework Plus extends your DbContext with must-haves features: Include Filter, Auditing, Caching, Query Future, Batch Delete, Batch Update, and more
https://entityframework-plus.net/
MIT License
2.26k stars 318 forks source link

Unable to cast object of type 'Z.EntityFramework.Plus.CreateEntityDataReader' to type 'Microsoft.Data.SqlClient.SqlDataReader' when entity has a Net Topology Suite object as a property #566

Closed arex388 closed 4 years ago

arex388 commented 4 years ago

Description

In my DbContext I have entities that use Net Topology Suite's Point and Polygon objects for properties. When attempting to use FutureValue() (and probably Future()) to select an entity results in an exception.

Exception

System.InvalidCastException: Unable to cast object of type 'Z.EntityFramework.Plus.CreateEntityDataReader' to type 'Microsoft.Data.SqlClient.SqlDataReader'.
   at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , Int32[] , ResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at Z.EntityFramework.Plus.QueryFutureValue`1.SetResult(DbDataReader reader)
   at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries()
   at Z.EntityFramework.Plus.QueryFutureValue`1.get_Value()
   at REMOVED.App.Portal.Devices.Arm.CommandHandler.Handle(Command command, CancellationToken cancellationToken) in E:\Software Development\REMOVED\REMOVED.App.Portal\Features\Devices\Arm.cs:line 42
   at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestExceptionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestExceptionActionProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestPostProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at MediatR.Pipeline.RequestPreProcessorBehavior`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next)
   at REMOVED.App.Portal.Devices.DevicesController.Arm(Int32 id) in E:\Software Development\REMOVED\REMOVED.App.Portal\Features\Devices\DevicesController.cs:line 50
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   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 where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at REMOVED.App.ApplicationUserMiddleware.InvokeAsync(HttpContext context, ApplicationUserServices services) in E:\Software Development\REMOVED\REMOVED.App\Middlewares\ApplicationUserMiddleware.cs:line 49
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Arex388.AspNetCore.HtmlMinifierMiddleware.InvokeAsync(HttpContext context)
   at Arex388.AspNetCore.AntiFaviconMiddleware.InvokeAsync(HttpContext context)
   at StackExchange.Profiling.MiniProfilerMiddleware.Invoke(HttpContext context) in C:\projects\dotnet\src\MiniProfiler.AspNetCore\MiniProfilerMiddleware.cs:line 107
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

EF Plus seems to be having a hard time with NTS, but it is the officially recommended library for geospatial data with SQL Server so I'm kind of stuck.

Further technical details

JonathanMagnan commented 4 years ago

Hello @arex388 ,

Thank you for reporting. We will look at it.

I believe we need now to find another solution to handle the QueryFuture for 3.x

arex388 commented 4 years ago

Hey @JonathanMagnan ,

For now I've got a bandaid where I've got computed columns to project the geography to a varchar(max), then I do a bunch of string splitting client side and re-create the Point or Polygon. Works for now.

I take it by your comment that EF Core 3.X+ is making things difficult?

JonathanMagnan commented 4 years ago

Initially, we only had the issue with Oracle since they were casting our internal command into a OracleCommand in their ExecuteReader method (or somewhere else, I'm not 100% sure to remember).

But a few weeks, someone reported a similar issue with PostgreSQL and now you with SQL Server.

The code was initially made for EF Core 2.x, so perhaps, we could find a better solution with EF Core 3.x

djjeffg382 commented 4 years ago

Just a note, this same issue occurs with .IncludeOptimized as well.

djjeffg382 commented 4 years ago

Hey @arex388 , Just a thought, but you could STAsText() in your computed column, which converts the Geography's to Well known Text (WKT). Then on the client side, use NetTopology to convert the WKT back to your point or polygon. Just a thought, but it may simplify your complexity a bit until a fix is found.

arex388 commented 4 years ago

@djjeffg382 I updated my computed columns to your recommendation and it's definitely much easier to re-create them back on the client side now. Thanks!

JonathanMagnan commented 4 years ago

Hello @arex388 and @djjeffg382 ,

We really took a lot of time in the past 2 weeks to find a solution but unfortunately, we didn't find one that worked correctly ;(

The IncludeOptimized method indeed uses the QueryFuture feature under the hood, so as you reported @djjeffg382 , the same issue is found on this one.

We will sure re-visit this issue in the future but for now, I guess we need to "abandon" it for a few weeks since we don't make any good progress at this moment ;(

steven62f commented 4 years ago

Any news about this problem ? I have the same error in my project with the use of the IncludeOptimized instruction on an object that contains a Point (NetTopologySuite) property. This problem is very annoying :(

System.InvalidCastException: Unable to cast object of type 'Z.EntityFramework.Plus.CreateEntityDataReader' to type 'Microsoft.Data.SqlClient.SqlDataReader'.
   at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , Int32[] , ResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at Z.EntityFramework.Plus.QueryFutureValue`1.SetResult(DbDataReader reader)
   at Z.EntityFramework.Plus.QueryFutureBatch.ExecuteQueries()
   at Z.EntityFramework.Plus.QueryFutureValue`1.get_Value()
   at Z.EntityFramework.Plus.QueryIncludeOptimizedProvider`1.Execute[TResult](Expression expression)
   at Z.EntityFramework.Plus.QueryIncludeOptimizedProvider`1.<>c__DisplayClass14_0`1.<ExecuteAsyncTask>b__0()
   at System.Threading.Tasks.Task`1.InnerInvoke()
   at System.Threading.Tasks.Task.<>c.<.cctor>b__274_0(Object obj)
   at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
steven62f commented 4 years ago

Hello @JonathanMagnan , do you have any idea on when this problem should be resolved?

Know if I'm patient or if I'm going for another solution.

JonathanMagnan commented 4 years ago

Hello @StevenHanquez ,

We have not done any progression. We need to find another way to make this feature since it break inside of the provider which makes some cast.

So you should probably go with another solution since we don't know when it will be fixed ;(

arex388 commented 4 years ago

Hey Jonathan,

Just wanted to ask if there was any hope for this to work again? Maybe in EF Core 5?

JonathanMagnan commented 4 years ago

I will ask my developer to look if there is some hope with the current EF Core 5 preview-8

JonathanMagnan commented 4 years ago

Unfortunately, we didn't succeed @arex388 ,

The cast is done inside Entity Framework.

The only way to fix it is probably to re-write some parts of this feature to remove some requirement such as using some custom reader.

At this moment, due to some time limitation, that's currently impossible but that's definitely something we will need to investigate to make sure this library stay up to date.

arex388 commented 4 years ago

Ok. Unfortunate but it is what it is. Thanks for taking a look again and hopefully in the future this can be resolved. Thanks!

JonathanMagnan commented 4 years ago

Hello arex388,

Thanks for your comprehension

Don't hesitate if you have any questions.

Best regards

Jon