避免lazyloader属性
Posted
技术标签:
【中文标题】避免lazyloader属性【英文标题】:Avoid lazyloader attribute 【发布时间】:2018-09-05 15:01:22 【问题描述】:我一直在寻找如何避免返回没有属性 lazyLoader 的列表,我想继续使用lazyLoader,但我不想在返回整个列表时返回属性来自我的控制器的实体
我正在使用 .NET 核心。
[
"lazyLoader": ,
"id": "id1"
"name": "name"
,
"lazyLoader": ,
"id": "id2",
"name": "name2"
]
【问题讨论】:
您可以将序列化程序配置为使用选择加入策略并将序列化程序属性附加到实体属性上。 或者只是装饰你想用 JsonIgnoreAttribute newtonsoft.com/json/help/html/…抑制的属性 Jsonignore 它,当你在一个类中有一个真实的属性但从框架中添加了lazyloader时工作 我会尝试 de serializer 可能是一个解决方案。 感谢@GertArnold 帮助我找到解决方案。序列化器就是解决方案 【参考方案1】:您可以选择您的集合,仅检索其余数据。 这样你的对象就根本没有 Navigation 属性。
db.YourCollection.Where(your condition)Select(x => new id = x.id , name = x.name );
【讨论】:
【参考方案2】:在 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”属性可能会再次出现。我没有测试过,所以不能肯定。
【讨论】:
【参考方案3】:我知道这是旧的,但添加
public boolean ShouldSerializeLazyLoader() return false;
到你想要序列化的那些树下的所有类,你会得到一个惰性加载器免费的 JSON。
参考:https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm
【讨论】:
【参考方案4】:此问题的检查答案仅适用于根对象,如果我们有许多嵌套的延迟加载对象,则此解决方案将不起作用。 虽然@Marcello-Barbiani 的回答是正确的,但是把这个函数加到我们所有的实体上并不是一个好办法。
最好的方法是创建一个从 DefaultContractResolver 派生的新 ContractResolver 并检查属性是否为 Lazyloader 然后跳过它,如下所示:
public class NonLazyloaderContractResolver : DefaultContractResolver
public new static readonly NonLazyloaderContractResolver Instance = new NonLazyloaderContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyName == "LazyLoader")
property.ShouldSerialize = i => false;
return property;
添加上面的类之后,在序列化对象时通过 JsonSerializerSettings 传递它:
var json = JsonConvert.SerializeObject(newProduct, new JsonSerializerSettings()
ContractResolver = new NonLazyloaderContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore );
最后,如果您使用的是 asp.net core 或 asp.net core webapi,请将此合同添加为 startup.cs 文件中的默认contractresolver:
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
options.SerializerSettings.ContractResolver = new NonLazyloaderContractResolver();
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
);
【讨论】:
以上是关于避免lazyloader属性的主要内容,如果未能解决你的问题,请参考以下文章
我的具有许多关系的属性必须使用 ICollection 来支持 Entity Framework 4.1 中的 LazyLoading?
Ef core LazyLoading - 访问集合类型的嵌套导航属性引发 DetachedLazyLoadingWarning 错误