我有一个属性为JObject的实体,我需要能够针对这些属性使用DbFunctions。
当我执行该项目时,该项目将引发一个异常,说明DbFunction不允许使用JObject类型的参数。
实体就像...
public class OrchestrationRun
{
public long Id { get; set; }
public JObject MetaData { get; set; }
public JObject SystemMetaData { get; set; }
}
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();
}
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)
);
}
}
我要执行的查询是...
var dbResponse = (from or in this.dbContext.OrchestrationRun
where MyDbContext.JsonValue(or.MetaData,"$.Product.ProductCategoryName") == "EXAMPLE"
select new
{
Id = or.Id,
CategoryId = "EXAMPLE"
}
).ToList();
注意: 在DbContext实例化时发生异常。因此,永远不会调用该查询。
抛出的异常是...
System.InvalidOperationException:DbFunction'MyDbContext.JsonValue'的参数'column'具有无效的类型'JObject'。确保参数类型可以被当前提供者映射。 在Microsoft.EntityFrameworkCore.Infrastructure.RelationalModelValidator.ValidateDbFunctions(IModel模型) 在Microsoft.EntityFrameworkCore.Internal.SqlServerModelValidator.Validate(IModel模型) 在Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ValidatingConvention.Apply(InternalModelBuilder modelBuilder)
答案 0 :(得分:1)
以下代码适用于完全相同的情况。
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)");
下面的一行神奇地将JObject
列转换为NVARCHAR(MAX)
或任何您的字符串数据类型。
答案 1 :(得分:0)
感谢 Raghu,您的回答对我帮助很大。对于可能来到这里并希望将转换与 json 函数混合并使用最新的 EF Core 5.0 更新 Raghu 的答案的用户:
jsonvalue 函数:
public static class JsonExtensions
{
public static string JsonValue(object expression, string path) => throw new InvalidOperationException($"{nameof(JsonValue)} cannot be called client side");
}
在 DbContext OnModelCreating 中:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var jsonValueMethodInfo = typeof(JsonExtensions).GetRuntimeMethod(nameof(JsonExtensions.JsonValue), new[] { typeof(string), typeof(string) });
modelBuilder
.HasDbFunction(jsonValueMethodInfo)
.HasTranslation(args => new SqlFunctionExpression("JSON_VALUE", args, nullable: true, argumentsPropagateNullability: new[] { false, false }, typeof(string), null))
.HasParameter("expression").Metadata.TypeMapping = new StringTypeMapping("NVARCHAR(MAX)"); // conversion
[...]
// example of conversion of a json property
entity.Property(e => e.AdditionalProperties)
.HasColumnName("AdditionalJson")
.HasConversion(
v => Newtonsoft.Json.JsonConvert.SerializeObject(v, new Newtonsoft.Json.JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore }),
v => Newtonsoft.Json.JsonConvert.DeserializeObject<AdditionalUserProperties>(v)
);
}
然后您就可以使用具有转换属性的扩展方法...例如:
var testId = (from u in this.Users
join e in this.Employees.IgnoreQueryFilters() on JsonExtensions.JsonValue(u.AdditionalProperties, "$." + nameof(AdditionalUserProperties.PersonalId)) equals e.PersonalId
where u.Id == userId
select e.Id).FirstOrDefault();
生成的sql:
[...][e] ON JSON_VALUE([u].[AdditionalJson], N'$.PersonalId') = [e].[PersonalId][...]