Entity framework 避免lazyloader属性

Entity framework 避免lazyloader属性,entity-framework,asp.net-core,lazy-loading,c#-2.0,Entity Framework,Asp.net Core,Lazy Loading,C# 2.0,我一直在寻找如何避免返回没有属性的列表,我想继续使用lazyLoader,但我不想在从控制器返回实体的整个列表时返回属性 我正在使用.NETCore [ { "lazyLoader": {}, "id": "id1" "name": "name" }, { "lazyLoader": {}, "id": "id2", "name": "name2" } ] 您可以选择只检索其余数据的集合。 这样,您的对象将根本不具有导航属性 db

我一直在寻找如何避免返回没有属性的列表,我想继续使用lazyLoader,但我不想在从控制器返回实体的整个列表时返回属性

我正在使用.NETCore

[
  {
    "lazyLoader": {},
    "id": "id1"
    "name": "name"
  },
  {
    "lazyLoader": {},
    "id": "id2",
    "name": "name2"
  }
]

您可以选择只检索其余数据的集合。 这样,您的对象将根本不具有导航属性

db.YourCollection.Where(your condition)Select(x => new { id = x.id , name = x.name } );

在实体框架中,如果有一个对象的一个或多个属性使用延迟加载,请使用GetType().name检查其运行时类型名称。例如,对于Car类的对象,您会注意到运行时类型实际上是一个名为CarProxy的对象,它是实体框架使用反射创建的临时内存中类型。这个“伪”代理类的基类型是Car,它具有所有原始Car属性,但包含一个额外的名为LazyLoader的属性,用于可能需要它的属性

如果进一步检查此“fake”CarProxy类型,还将看到Assembly.IsDynamic=true,这表明该类是使用反射动态创建的(请参阅):

幸运的是,Newtonsoft.JsonJsonConvert.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”属性可能会再次出现。我还没有测试过它,所以我不能肯定。

我知道这是旧的,但是添加

public boolean ShouldSerializeLazyLoader() { return false; }
对于要序列化的类树下的所有类,您将获得一个无lazyloader的JSON


参考:

此问题的选中答案仅适用于根对象,如果我们有许多嵌套的lazyloaded对象,此解决方案将不起作用。 虽然@的答案是正确的,但将此函数添加到所有实体中并不是一个好方法

最好的方法是创建一个从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文件中将此合约添加为默认合约解析程序:

services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddJsonOptions(options =>
        {
            options.SerializerSettings.ContractResolver = new NonLazyloaderContractResolver();
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });

您可以将序列化程序配置为使用opt-in策略,并将序列化程序属性固定到实体属性上。或者只使用JSONIGNOREATTRITE Jsonignore it修饰要抑制的属性,当你在一个类中有一个真正的属性,但是lazyloader是从Framework中添加的,那么它就可以工作了。我会尝试反序列化程序,也许可以解决这个问题。感谢@GertArnold帮助我找到解决方案。序列化程序是解决方案
services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
        .AddJsonOptions(options =>
        {
            options.SerializerSettings.ContractResolver = new NonLazyloaderContractResolver();
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        });