我正在尝试json_value。目标是在数据库中创建动态模型,该模型可以使用json包含任何类型的数据。
这是模型:
public class DynamicModel
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ID { get; set; }
public string TableName { get; set; } = "MyTable";
public Guid? Container { get; set; } = null; //Parent who hold this data for many-one relation
public string Content { get; set; } = ""; //JSON content
public bool DeleteOnCascade { get; set; } = false;
public DateTime DateCreated { get; set; } = DateTime.UtcNow;
public DateTime LastEdited { get; set; } = DateTime.UtcNow;
}
例如,如果Content
包含:
"{ \"name\":\"John\", \"age\":30, \"cars\":[] }"
如果我将汽车放在同一行中,则会出现问题,因为数据太大,访问数据效率不高。
因此,我认为将汽车的嵌套列表分为不同的行会更好:
var car = new DynamicModel() {
Id = ...,
TableName = "Car",
Container = //the parent ID of the above example (one - many relation),
DeleteOnCascade = true, //Gets deleted if the parent gets deleted,
...
}
这就是我修改实体框架以能够访问json_value的方法:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Conventions.Add(new RegisterJsonValueFunctionConvention());
}
然后
public static class JH
{
// Than define your function
[DbFunction("CodeFirstDatabaseSchema", "JSON_VALUE")]
public static string JsonValue(string expression, string path)
{
throw new NotSupportedException();
}
}
然后
public class RegisterJsonValueFunctionConvention : IStoreModelConvention<EdmModel>
{
public void Apply(EdmModel item, DbModel model)
{
var expressionParameter = FunctionParameter.Create("expression", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In);
var pathParameter = FunctionParameter.Create("path", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.In);
var returnValue = FunctionParameter.Create("result", GetStorePrimitiveType(model, PrimitiveTypeKind.String), ParameterMode.ReturnValue);
CreateAndAddFunction(item, "JSON_VALUE", new[] { expressionParameter, pathParameter }, new[] { returnValue });
}
protected EdmFunction CreateAndAddFunction(EdmModel item, string name, IList<FunctionParameter> parameters, IList<FunctionParameter> returnValues)
{
var payload = new EdmFunctionPayload { StoreFunctionName = name, Parameters = parameters, ReturnParameters = returnValues, Schema = GetDefaultSchema(item), IsBuiltIn = true };
var function = EdmFunction.Create(name, GetDefaultNamespace(item), item.DataSpace, payload, null);
item.AddItem(function);
return function;
}
protected EdmType GetStorePrimitiveType(DbModel model, PrimitiveTypeKind typeKind)
{
return model.ProviderManifest.GetStoreType(TypeUsage.CreateDefaultTypeUsage(PrimitiveType.GetEdmPrimitiveType(typeKind))).EdmType;
}
protected string GetDefaultNamespace(EdmModel layerModel)
{
return layerModel.GlobalItems.OfType<EdmType>().Select(t => t.NamespaceName).Distinct().Single();
}
protected string GetDefaultSchema(EdmModel layerModel)
{
return layerModel.Container.EntitySets.Select(s => s.Schema).Distinct().SingleOrDefault();
}
}
最后,这就是我访问值的方式:
var x = db.DynamicData
.Where(m => JH.JsonValue(m.Content, "$.name").Equals("John"))
.Select(m => JH.JsonValue(m.Content, "$.age"))
.FirstOrDefault();
我想知道是否有使用Linq查询访问cars
的便捷方法?
现在我必须先获取x
值,然后查找具有cars
值的Container
作为x.ID
,获取列表,然后追加到cars:[]
的位置,这确实需要时间和内存来处理它。
那你觉得家伙如何?有没有简便的方法可以更简单地实现这一目标?
答案 0 :(得分:1)
可以想象,您可以注册另一个数据库函数来使用JSON_QUERY()函数,该函数可用于从JSON数据中选择数组和对象。