避免 lazyloader 属性

Avoid lazyloader attribute

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

我正在使用 .NET 核心。

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

您可以进行 select 收集,仅检索其余数据。 这样您的对象将根本没有导航 属性。

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

在 Entity Framework 中,如果您有一个对象,其中一个或多个属性使用延迟加载,请使用 GetType().Name 检查其运行时类型名称。例如,对于 Car class 的对象,您会注意到运行时类型实际上是一种叫做 CarProxy 的东西,它是Entity Framework 使用 反射 创建的临时内存类型。此 "fake" 代理 class 的基本类型是 Car,具有所有原始 Car 属性,但包括一个额外的一个叫做 LazyLoader 用于可能需要它的属性。

如果您进一步检查此 "fake" CarProxy 类型,您还会看到 Assembly.IsDynamic = true,这表明 class 是使用反射动态创建的(参见 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" 属性 可能会再次出现。我还没有测试过,所以我不能肯定。

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

public boolean ShouldSerializeLazyLoader() { return false; }

到所有 类 你想要序列化的树下,你将免费获得一个 lazyloader JSON。

参考:https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm

这个问题的检查答案只适用于根对象,如果我们有很多嵌套的延迟加载对象,这个解决方案将不起作用。 虽然 @ 的答案是正确的,但将此功能添加到我们拥有的所有实体并不是一个好方法。

最好的方法是创建一个从 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;
        }
}

在上面添加之后 class 在序列化对象时通过 JsonSerializerSettings 传递它:

var json = JsonConvert.SerializeObject(newProduct, new JsonSerializerSettings() {
                ContractResolver = new NonLazyloaderContractResolver(),
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                DefaultValueHandling = DefaultValueHandling.Ignore });

最后,如果您使用的是 asp.net 核心或 asp.net 核心 webapi,请在 startup.cs 文件中添加此合约作为默认合约解析器:

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