question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot cast from 'String' to 'JsonElement' exception when mapping to JSON column

See original GitHub issue

Code

using Microsoft.EntityFrameworkCore;

public enum OrderStatus
{
    Pending,
    Shipped
}

public class StreetAddress
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public OrderStatus Status { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

public class MyContext : DbContext
{
    public DbSet<Order> Orders { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseMySql(
                "Server=localhost;Database=test;User=root",
                new MySqlServerVersion(new System.Version(8, 0)),
                o => o.UseMicrosoftJson());
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>()
            .OwnsOne(
                p => p.ShippingAddress,
                nb => nb.ToJson());
    }
}

public static class Program
{
    public static void Main(string[] args)
    {
        using var context = new MyContext();

        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        context.Add(new Order
        {
            Id = 101,
            Status = OrderStatus.Pending,
            ShippingAddress = new StreetAddress { City = "London", Street = "221 B Baker St" }
        });

        context.SaveChanges();
    }
}

Steps to reproduce

  1. Build
  2. Add migration
  3. Run

The issue

Throws a DbUpdateException on context.SaveChanges(), with an inner InvalidCastException saying that it cannot cast from ‘String’ to ‘JsonElement’.

Exception message: Invalid cast from 'System.String' to 'System.Text.Json.JsonElement'.
Stack trace:
   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   at System.String.System.IConvertible.ToType(Type type, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter`2.Sanitize[T](Object value)
   at Microsoft.EntityFrameworkCore.Storage.ValueConversion.ValueConverter`2.<>c__DisplayClass4_0`2.<SanitizeConverter>b__1(Object v)
   at Microsoft.EntityFrameworkCore.Storage.RelationalTypeMapping.CreateParameter(DbCommand command, String name, Object value, Nullable`1 nullable, ParameterDirection direction)
   at Microsoft.EntityFrameworkCore.Storage.Internal.TypeMappedRelationalParameter.AddDbParameter(DbCommand command, Object value)
   at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalParameterBase.AddDbParameter(DbCommand command, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.CreateDbCommand(RelationalCommandParameterObject parameterObject, Guid commandId, DbCommandMethod commandMethod)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)

Further technical details

Database version: MySQL v8.0.27 and MariaDB v10.6.11 Operating system: Windows 10 build 19044.2486 Pomelo.EntityFrameworkCore.MySql version: 7.0.0 Microsoft.AspNetCore.App: 6.0.13 and 7.0.2

Other info

I tried this on multiple machines and always end up with the same exception. It only happens when aggregating to JSON (nb.ToJson()).

Issue Analytics

  • State:open
  • Created 8 months ago
  • Reactions:1
  • Comments:5

github_iconTop GitHub Comments

1reaction
Angelinsky7commented, Jun 5, 2023

@lauxjpn does it mean that we cannot use OwnsOne or OwnsMany with ToJson call ? Because it’s actually not possible to something like this

builder.Property(p => p.Data).HasColumnType("json")
builder .OwnsOne(p => p.Data, dataBuilder => {
  dataBuilder.ToJson("data");
  dataBuilder.OwnsMany(p => p.Items); // Not necessary
});

The 2 properties are mutually exclusive : The property or navigation 'Data' cannot be added to the entity type '' because a property or navigation with the same name already exists on entity type ''.

What would be the workaround to have OwnEntities with JSON representation in database with the current version of Pomelo ?

Thanks !

Edit: For me the current exception is : InvalidOperationException: This node should be handled by provider-specific sql generator.

Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitJsonScalar(JsonScalarExpression jsonScalarExpression)
Microsoft.EntityFrameworkCore.Query.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal.MySqlQuerySqlGenerator.VisitExtension(Expression extensionExpression)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitProjection(ProjectionExpression projectionExpression)
Microsoft.EntityFrameworkCore.Query.SqlExpressionVisitor.VisitExtension(Expression extensionExpression)
Pomelo.EntityFrameworkCore.MySql.Query.ExpressionVisitors.Internal.MySqlQuerySqlGenerator.VisitExtension(Expression extensionExpression)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.<VisitSelect>b__21_0(ProjectionExpression e)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.GenerateList<T>(IReadOnlyList<T> items, Action<T> generationAction, Action<IRelationalCommandBuilder> joinAction)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.VisitSelect(SelectExpression selectExpression)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.GenerateRootCommand(Expression queryExpression)
Microsoft.EntityFrameworkCore.Query.QuerySqlGenerator.GetCommand(Expression queryExpression)
Microsoft.EntityFrameworkCore.Query.Internal.RelationalCommandCache.GetRelationalCommandTemplate(IReadOnlyDictionary<string, object> parameters)
Microsoft.EntityFrameworkCore.Internal.RelationCommandCacheExtensions.RentAndPopulateRelationalCommand(RelationalCommandCache relationalCommandCache, RelationalQueryContext queryContext)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<T>+AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync<TState, TResult>(TState state, Func<DbContext, TState, CancellationToken, Task<TResult>> operation, Func<DbContext, TState, CancellationToken, Task<ExecutionResult<TResult>>> verifySucceeded, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable<T>+AsyncEnumerator.MoveNextAsync()
System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable<TResult>+ConfiguredValueTaskAwaiter.GetResult()
Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync<TSource>(IAsyncEnumerable<TSource> asyncEnumerable, CancellationToken cancellationToken)
Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync<TSource>(IAsyncEnumerable<TSource> asyncEnumerable, CancellationToken cancellationToken)

With version :

<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="7.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Json.Microsoft" Version="7.0.0" />
1reaction
lauxjpncommented, Apr 12, 2023

Pomelo has extended JSON support for both, the Microsoft stack and the Newtonsoft stack. Because we already implemented JSON support a couple of years ago, it works a bit different than the simple JSON support now supported by EF Core.

For some (older) sample code, with lots of different ways to use JSON, see https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql/issues/14#issuecomment-725257107.

The basics steps are to reference either the Pomelo.EntityFrameworkCore.MySql.Json.Microsoft or Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft NuGet package, call .UseMicrosoftJson() or .UseNewtonsoftJson() and set the column type to json in the model (e.g. by using .HasColumnType("json")) for all columns that you want to use with JSON.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Class cast Exception during JSON Parsing - java
It fails because the result of parsing is not a String, nor Map<String,String> and not even a Map<String,Map<String,String>>.
Read more >
Convert String to JsonObject with Gson
Learn a couple of methods for converting a JSON String into a JsonObject using the Gson library in Java.
Read more >
3 ways to convert String to JSON object in Java? Examples
Hello Aishwarya, you need to use json-simple-1.1.1.jar to use JSONParser and JSONObject, you can download the JAR file from Maven repository ...
Read more >
Jackson - Convert JSON string to Map
In Jackson, we can use mapper.readValue(json, Map.class) to convert a JSON string to a Map. P.S Tested with Jackson 2.9.8. pom.xml.
Read more >
Jackson: java.util.LinkedHashMap cannot be cast to X
ClassCastException : java.util.LinkedHashMap cannot be cast to X when we try to deserialize JSON or XML into a collection of objects.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found