我懒于将表数据加载到JSON结果中,然后将它们拖到前端应用程序中。但是当我获得这些数据时,我注意到响应中存在不必要的元素,即空元素。因此,我的PUT
或更新操作不适用于这些内部JSON属性。
{
"image":null,
"paragraph":null,
"question":{
"grid":null,
"elements":[
],
"offeredAnswers":[
],
"lazyLoader":{
},
"id":"1",
"text":"How can we serve you better?",
"type":"textarea",
"questionRequired":false,
"pageFlowModifier":false,
"gridId":null,
"min":null,
"max":null
},
"lazyLoader":{
}
}
如果我更改text
的值,它将不会被更新,但是如果我更改paragraph
,它将在数据库中被更改。
这里有一个名为lazyLoader
的新属性,我也需要摆脱它。和elements
,offeredAnswers
实际上是不需要的,因为它们为空。我通过将virtual
关键字添加到引用的类来实现延迟加载。
public partial class Questions
{
public Questions()
{
Elements = new HashSet<Elements>();
OfferedAnswers = new HashSet<OfferedAnswers>();
}
public string Id { get; set; }
public string Text { get; set; }
public string Type { get; set; }
public bool QuestionRequired { get; set; }
public bool PageFlowModifier { get; set; }
public int? GridId { get; set; }
public long? Min { get; set; }
public long? Max { get; set; }
public virtual Grids Grid { get; set; }
public virtual ICollection<Elements> Elements { get; set; }
public virtual ICollection<OfferedAnswers> OfferedAnswers { get; set; }
}
我在Startup.cs
文件中有这一行来停止引用循环处理,因为如果没有这样的话,POST
操作就不会起作用,因为我发布的JSON
对象非常复杂,并且内部有参考循环。
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
并且我启用了延迟加载代理。
services.AddDbContext<RDS_Context>
(options => options.UseLazyLoadingProxies().UseSqlServer(connection));
答案 0 :(得分:2)
您可以将数据库实体模型与想要在前端显示的模型分开。映射所需的实体模型的属性,并将其包含在新的前端模型中。
无需实施新模型的更快方法是使用匿名对象,例如:
myDbContext.MyObjects.Select(x => new { Prop1 = x.Property1, Prop2 = x.Property2 });
如果您的实体类中确实具有LazyLoader属性(例如,注入ILazyLoader as described here),您可以改用JsonIgnore attribtue装饰它。
答案 1 :(得分:1)
您可以像这样在Object
中Array
进行迭代,从而从json中删除空的JProperty
和JObject
class Program
{
static void Main(string[] args)
{
string json = File.ReadAllText(@"C:\Users\xxx\source\repos\ConsoleApp4\ConsoleApp4\Files\json6.json");
JObject data = JObject.Parse(json);
//Getting all those children that have value are empty from outer json
var result1 = data.Children<JProperty>()
.Where(x => (x.Value.Type == JTokenType.Object) && !x.Value.HasValues)
.ToList();
//Getting all those children that have value are empty from "question" object
var result2 = data["question"].Children<JProperty>()
.Where(x => (x.Value.Type == JTokenType.Object && !x.Value.HasValues) || (x.Value.Type == JTokenType.Array && !x.Value.HasValues))
.ToList();
//Remove all above empty object or arrays
result1.ForEach(x => x.Remove());
result2.ForEach(x => x.Remove());
var obj = data.ToObject<JObject>();
Console.WriteLine(obj);
Console.ReadLine();
}
}
输出:
注意::如果您想在整个json中仅删除空的lazyLoader
对象,请在上面的代码中使用以下几行。
//Getting "lazyLoader" children that have value are empty from outer json
var result1 = data.Children<JProperty>()
.Where(x => x.Value.Type == JTokenType.Object && !x.Value.HasValues && x.Name == "lazyLoader")
.ToList();
//Getting "lazyLoader" children that have value are empty from "question" object
var result2 = data["question"].Children<JProperty>()
.Where(x => (x.Value.Type == JTokenType.Object && !x.Value.HasValues && x.Name == "lazyLoader"))
.ToList();
输出:
答案 2 :(得分:1)
我知道已经有一个可接受的答案,但是基于a suggestion at EFCore repos和another SO answer it referenced,我将把这种替代方法留给那些只想摆脱lazyLoader属性的人
创建一个 CustomContractResolver.cs
public class CustomContractResolver : DefaultContractResolver
{
public static CustomContractResolver Instance { get; } = new CustomContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (member.Name == "LazyLoader")
{
property.Ignored = true;
}
return property;
}
}
并修改您的 Startup.cs ,ConfigureServices
方法以使用ContractResolver
services
.AddMvc(...)
.AddJsonOptions(options => {
options.SerializerSettings.ContractResolver = CustomContractResolver.Instance;
});
答案 3 :(得分:0)
在Entity Framework中,如果您有一个对象的一个或多个属性使用延迟加载,请使用GetType()。Name检查其运行时类型名称。例如,对于 Car 类的对象,您会注意到运行时类型实际上是名为 CarProxy 的东西,这是由Entity Framework创建的临时内存类型。使用反射。该“伪”代理类的基本类型是 Car ,并具有所有原始的 Car 属性,但还包括一个名为 LazyLoader 的附加属性。可能需要它。
如果您进一步检查这种“伪造的” CarProxy 类型,您还将看到 Assembly.IsDynamic = true ,这表明该类是动态创建的使用反射(请参阅documentation):
var TheCar = DBContext.Cars.Find(1);
Console.WriteLine(TheCar.GetType().Assembly.IsDynamic.ToString()); //will echo "true"
幸运的是, Newtonsoft.Json 在 JsonConvert.SerializeObject()方法上有一个替代,该方法允许我们提供基本类型,因此生成的JSON不会包含该类型不存在的属性。因此,要消除 LazyLoader 属性,只需提供对象的BaseType作为类型参数即可:
var TheCar = DBContext.Cars.Find(1);
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType);
要确保序列化时没有任何循环引用循环(使用延迟加载的可能性很高),请使用以下设置调用序列化器:
var TheCar = DBContext.Cars.Find(1);
var Settings = new Newtonsoft.Json.JsonSerializerSettings
{
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
};
var TheJSON = Newtonsoft.Json.JsonConvert.SerializeObject(TheCar, TheCar.GetType().BaseType, Settings);
注意:这可能仅在串行化器穿过对象时才在第一层深处起作用。如果您提供给序列化程序的对象还有更多的延迟加载子属性,则“ LazyLoader”属性可能会再次出现。我还没有测试过,所以不能确定。