EF 序列化实体为Json时的循环引用问题(不用自己写实体,不用匿名类型,不用EF的上下文属性)

时间:2021-05-24 22:19:16

自己写实体可以完美解决这个问题。(支持时间格式自定义)

用匿名类型也可以。

设置上下文方法如下:

(jz为数据库上下文对象)

jz.Configuration.ProxyCreationEnabled = false;
jz.Configuration.LazyLoadingEnabled = false;

不用这个的原因是Virtual属性也会生成。(只是占个位,[]里面没内容,但看着不爽)

我采用的方法是过滤掉Virtual属性的方法:

一个基于Json.net的类

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web; namespace AceepSystem.Models.Help
{
    public class JsonForEF : DefaultContractResolver
    {
        string[] props = null;         bool retain;         /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="props">传入的属性数组</param>
        /// <param name="retain">true:表示props是需要保留的字段  false:表示props是要排除的字段</param>
        public JsonForEF(string[] props, bool retain = true)
        {
            //指定要序列化属性的清单
            this.props = props;             this.retain = retain;
        }         protected override IList<JsonProperty> CreateProperties(Type type,         MemberSerialization memberSerialization)
        {
            IList<JsonProperty> list =
            base.CreateProperties(type, memberSerialization);
            //只保留清单有列出的属性
            return list.Where(p =>
            {
                if (retain)
                {
                    return props.Contains(p.PropertyName);
                }
                else
                {
                    return !props.Contains(p.PropertyName);
                }
            }).ToList();
        }
        public static string[] GetVirtualList<T>()
        {
            var stringType = typeof(T);
            var props = stringType.GetProperties();
            List<string> test = new List<string>();
            foreach (var prop in props)
            {
                if (prop.GetAccessors()[0].IsVirtual)
                {
                    test.Add(prop.Name);
                }
            }
            return test.ToArray();
        }
        public static JsonSerializerSettings GetJsonConfig<T>()
        {             JsonSerializerSettings jsetting = new JsonSerializerSettings();//过滤掉ef中的导航属性,无残留...
            jsetting.ContractResolver = new JsonForEF(
            JsonForEF.GetVirtualList<T>()//泛型方法传入当前要序列化的类型
            , false);//false为要排除的属性,true为要保留的属性(第一个参数为string[])
            jsetting.Converters.Add(new MyDateTimeConvertor());
            return jsetting;
        }
        public class MyDateTimeConvertor : DateTimeConverterBase
        {
            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                return DateTime.Parse(reader.Value.ToString());
            }             public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                writer.WriteValue(((DateTime)value).ToString("yyyy/MM/dd HH:mm"));
            }
        }
    }
}

和一个对PropertyInfo的扩展方法

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web; namespace AceepSystem.Models.Help
{
    public static class Virtual_Help
    {
      
        public static bool? IsVirtual(this PropertyInfo self)
        {
            if (self == null)
                throw new ArgumentNullException("self");             bool? found = null;             foreach (MethodInfo method in self.GetAccessors())
            {
                if (found.HasValue)
                {
                    if (found.Value != method.IsVirtual)
                        return null;
                }
                else
                {
                    found = method.IsVirtual;
                }
            }             return found;
        }
       
    }
}

使用方法如下

 string json = JsonConvert.SerializeObject(
               list,
                Formatting.Indented,
                JsonForEF.GetJsonConfig<dic_attribution>()
                );//转C#对象为Json数据