避免使用lazyloader属性

时间:2018-09-05 15:01:22

标签: entity-framework asp.net-core lazy-loading c#-2.0

我一直在寻找如何避免返回不带属性 lazyLoader 的列表的方法,我想继续使用lazyLoader,但是当我返回整个列表时不希望返回该属性我的控制者提供的实体

我正在使用.NET core。

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

4 个答案:

答案 0 :(得分:1)

在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”属性可能会再次出现。我还没有测试过,所以不能确定。

答案 1 :(得分:1)

此问题的选中答案仅适用于根对象,如果我们有许多嵌套的延迟加载对象,则此解决方案将不起作用。 尽管@ 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,请将此合同作为默认的contractresolver添加到startup.cs文件中:

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

答案 2 :(得分:0)

您只能对集合进行选择,而仅检索其余数据。 这样,您的对象将根本没有导航属性。

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

答案 3 :(得分:0)

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

public boolean ShouldSerializeLazyLoader() { return false; }

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

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