Pomelo.entityframeworkcore.mysql: InvalidOperationException: Calling ShapedQueryExpression.VisitChildren is not allowed. Visit expression manually for relevant part.

Created on 21 Apr 2020  路  5Comments  路  Source: PomeloFoundation/Pomelo.EntityFrameworkCore.MySql

Steps to reproduce

context.Set<T>().ToList();

The issue

The GetAll() Generic Repository Method doesn't work.

Exception message:
An unhandled exception occurred while processing the request.
InvalidOperationException: Calling ShapedQueryExpression.VisitChildren is not allowed. Visit expression manually for relevant part.
Microsoft.EntityFrameworkCore.Query.ShapedQueryExpression.VisitChildren(ExpressionVisitor visitor)



Stack trace:
Microsoft.EntityFrameworkCore.Query.ShapedQueryExpression.VisitChildren(ExpressionVisitor visitor)
Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal.MySqlCompatibilityExpressionVisitor.VisitExtension(Expression extensionExpression)
Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal.MySqlQueryTranslationPostprocessor.Process(Expression query)
Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor<TResult>(Expression query)
Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery<TResult>(Expression query, bool async)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore<TResult>(IDatabase database, Expression query, IModel model, bool async)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler+<>c__DisplayClass12_0<TResult>.<ExecuteAsync>b__0()
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore<TFunc>(object cacheKey, Func<Func<QueryContext, TFunc>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery<TResult>(object cacheKey, Func<Func<QueryContext, TResult>> compiler)
Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync<TResult>(Expression query, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<TResult>.GetAsyncEnumerator(CancellationToken cancellationToken)
Microsoft.AspNetCore.Mvc.Infrastructure.AsyncEnumerableReader.ReadInternal<T>(object value)
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor.ExecuteAsyncEnumerable(ActionContext context, ObjectResult result, object asyncEnumerable, Func<object, Task<ICollection>> reader)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_0<TFilter, TFilterAsync>(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext<TFilter, TFilterAsync>(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Further technical details

MySQL version: 10.4.12-MariaDB
Operating system: Linux 64 bits
Pomelo.EntityFrameworkCore.MySql version: 3.1.1
Microsoft.AspNetCore.App version: 3.1.201

Other details about my project setup:
Entity Framework 3.1.3

type-question

Most helpful comment

The following is not going to work:

```c#
public IEnumerable Registers { get; set; }


Firstly, it isn't going to work, because your `IRegister` entity defines the following public property:

```c#
public Type GetType {
    get { return type; }
    set { type = value; }
}

Since you don't ignore the property (at least you did not provide any FluentAPI model definition for it, so I have to assume, that there is none), EF Core will try to map the Type CLR type to a database store type, which it will not be able to.

You could however save a string with the type's name if that is enough for you. So instead of using your custom GetType, use something like the following instead:

```c#
[NotMapped]
public Type Type { get; set; }

public string TypeName
{
get => Type.FullName;
set => Type = Type.GetType(value);
}


You can then use the `Type` property in your app and use the `TypeName` property for database persistency.

---

Couple of side notes:

Because every object has a `GetType()` method and you are using a property with the same name here, you either want to change the name of your custom property, or use the `new` keyword (`public new Type GetType {}`). If you use my suggestion from above, this is of course not necessary, because this property does not exist anymore.

The `Get<T>` method of your repository does not need to call `AsEnumerable<T>()`, because it is using `.ToList()` anyway in the next line, which materializes the query as well. But then you return an `IEnumerable<T>` again, which does not make sense.

So either use this:

```c#
public IEnumerable<T> Get<T>()
    where T : class
    => Set<T>().AsEnumerable();

Or this:

c# public List<T> Get<T>() // or IList<T> where T : class => Set<T>().ToList();

Generally, I don't see any advantage to use an explicit repository pattern here at all. DbContext is already a unit-of-work pattern implementation and DbSet is already a repository pattern implementation. So if you don't have a good reason to put another facade around DbSet, you might want to consider using DbSet directly.

All 5 comments

What is the full LINQ query you are running? What is the actual type that is being used for T?

Just a call: context.Set().AsEnumerable(), T is a Simple Object with a ICollection Property.

But in fact, Looking with more attention I noted that Microsoft.EntityFrameworkCore.Tools and Microsoft.EntityFrameworkCore.Design are in 5.0 preview version.

Please post the actual LINQ query (the real one), the model classes of all entities involved in the query and the model definitions (FluentAPI) of the models involved.

Repository Method:

public IEnumerable<T> Get()
{
    var collection = context.Set<T>().AsEnumerable<T>();
    return collection.ToList();
}

LINQ query (the line when throw the Exception):

context.Set<Maintenance>().AsEnumerable<Maintenance>();

Model Classes:
```
public class Maintenance {
public Int32 Id { get; set; }
private Int32 maxLengthPerLine = 380;
public Int32 MaxLengthPerLine {
get { return maxLengthPerLine; }
set { maxLengthPerLine = value; }
}
public DateTime CreatedDate { get; set; }
public IEnumerable Registers { get; set; }
public Boolean IsGeneratedFile { get; private set; }
public DateTime? GeneratedDate { get; set; }
public Boolean IsRejectedFile { get; private set; }
public DateTime? RejectedDate { get; set; }

    public String DataOldJson { get; set; }

}

public abstract class IRegister {
public Int32 Id { get; set; }

    public Int32 MaintenanceFileLayoutId { get; set; }

    protected Type type;
    public Type GetType {
        get { return type; }
        set { type = value; }
    }

    public DateTime CreatedDate { get; set; }

}

The following is not going to work:

```c#
public IEnumerable Registers { get; set; }


Firstly, it isn't going to work, because your `IRegister` entity defines the following public property:

```c#
public Type GetType {
    get { return type; }
    set { type = value; }
}

Since you don't ignore the property (at least you did not provide any FluentAPI model definition for it, so I have to assume, that there is none), EF Core will try to map the Type CLR type to a database store type, which it will not be able to.

You could however save a string with the type's name if that is enough for you. So instead of using your custom GetType, use something like the following instead:

```c#
[NotMapped]
public Type Type { get; set; }

public string TypeName
{
get => Type.FullName;
set => Type = Type.GetType(value);
}


You can then use the `Type` property in your app and use the `TypeName` property for database persistency.

---

Couple of side notes:

Because every object has a `GetType()` method and you are using a property with the same name here, you either want to change the name of your custom property, or use the `new` keyword (`public new Type GetType {}`). If you use my suggestion from above, this is of course not necessary, because this property does not exist anymore.

The `Get<T>` method of your repository does not need to call `AsEnumerable<T>()`, because it is using `.ToList()` anyway in the next line, which materializes the query as well. But then you return an `IEnumerable<T>` again, which does not make sense.

So either use this:

```c#
public IEnumerable<T> Get<T>()
    where T : class
    => Set<T>().AsEnumerable();

Or this:

c# public List<T> Get<T>() // or IList<T> where T : class => Set<T>().ToList();

Generally, I don't see any advantage to use an explicit repository pattern here at all. DbContext is already a unit-of-work pattern implementation and DbSet is already a repository pattern implementation. So if you don't have a good reason to put another facade around DbSet, you might want to consider using DbSet directly.

Was this page helpful?
0 / 5 - 0 ratings