将 EF Core 约定和 DBFunction 混合用于 JObject 属性

Leo*_*ger 6 mapping entity-framework .net-core dbfunctions

我有一个具有 JObject 类型属性的实体,并且我需要能够针对这些属性使用 DbFunctions。

当我执行时,项目抛出一个异常,指出 DbFunction 不允许使用 JObject 类型的参数。

实体就像...

public class OrchestrationRun
{
   public long Id { get; set; }
    public JObject MetaData { get; set; }
    public JObject SystemMetaData { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

DbContext看起来像......

public class MyDbContext : DbContext
{
    public MyDbContext(DbContextOptions options)
        : base(options)
    {
    }

    public virtual DbSet<OrchestrationRun> OrchestrationRun { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new OrchestrationRunConfiguration());

       // DbFunction mapping for JSON_VALUE
       modelBuilder.HasDbFunction( typeof(MyDbContext).GetMethod(nameof(JsonValue)))
                      .HasName("JSON_VALUE")
                      .HasSchema("");
    }

    // DbFunction
    public static string JsonValue(JObject column, [NotParameterized] string path) => throw new NotSupportedException();
}
Run Code Online (Sandbox Code Playgroud)

OrchestrationRunConfiguration...

public class OrchestrationRunConfiguration : IEntityTypeConfiguration<OrchestrationRun>
{
    public void Configure(EntityTypeBuilder<OrchestrationRun> builder)
    {
        builder.Property(e => e.MetaData).HasConversion(
            jObject => jObject != null ? jObject.ToString(Formatting.None) : null,
            json => string.IsNullOrWhiteSpace(json) ? null : JObject.Parse(json)
        );

        builder.Property(e => e.SystemMetaData).HasConversion(
             jObject => jObject != null ? jObject.ToString(Formatting.None): null,
             json => string.IsNullOrWhiteSpace(json) ? null : JObject.Parse(json)
         );
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图执行的查询是...

var dbResponse = (from or in this.dbContext.OrchestrationRun
where MyDbContext.JsonValue(or.MetaData,"$.Product.ProductCategoryName") == "EXAMPLE"
select new
       {
          Id = or.Id,
          CategoryId = "EXAMPLE"
       }

    ).ToList();
Run Code Online (Sandbox Code Playgroud)

注意:异常发生在DbContext实例化时。因此,该查询永远不会被调用。

抛出的异常是...

System.InvalidOperationException:DbFunction“MyDbContext.JsonValue”的参数“column”具有无效类型“JObject”。确保当前提供程序可以映射参数类型。在 Microsoft.EntityFrameworkCore.Infrastruct.RelationalModelValidator.ValidateDbFunctions(IModel 模型) 在 Microsoft.EntityFrameworkCore.Internal.SqlServerModelValidator.Validate(IModel 模型) 在 Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)

Rag*_*ghu 7

下面的代码适用于完全相同的场景。

            var jsonValueMethod = typeof(MyDbContext).GetMethod(nameof(MyDbContext.JsonValue));

            builder.HasDbFunction(jsonValueMethod)
                .HasTranslation(args => {
                    return SqlFunctionExpression.Create("JSON_VALUE", args, jsonValueMethod.ReturnType, null);
                })
                .HasParameter("column").Metadata.TypeMapping = new StringTypeMapping("NVARCHAR(MAX)");
Run Code Online (Sandbox Code Playgroud)

JObject下面的行具有将列转换为字符串NVARCHAR(MAX)数据类型或任何字符串数据类型的魔力。

更新:以下是 EF Core 5 及更高版本的语法。

        protected override void OnModelCreating(ModelBuilder builder)
        {
            ....

            var jsonValueMethod = typeof(QueryExtentions).GetMethod(nameof(QueryExtentions.JsonValue));
            var stringTypeMapping = new StringTypeMapping("NVARCHAR(MAX)");

            builder
                .HasDbFunction(jsonValueMethod)
                .HasTranslation(args => new SqlFunctionExpression("JSON_VALUE", args, nullable: true, argumentsPropagateNullability: new[] { false, false }, jsonValueMethod.ReturnType, stringTypeMapping))
                .HasParameter("column").Metadata.TypeMapping = stringTypeMapping;
            .....
Run Code Online (Sandbox Code Playgroud)

  • @Nexus .HasTranslation(args =&gt; new SqlFunctionExpression(“JSON_VALUE”,args,可为空:true,argumentsPropagateNullability:new [] { false,false },typeof(字符串),null)) (3认同)