Entity framework 序列化实体框架问题

Entity framework 序列化实体框架问题,entity-framework,serialization,json,Entity Framework,Serialization,Json,和其他一些人一样,我在序列化实体框架对象时遇到了问题,因此我无法通过AJAX以JSON格式发送数据 我有以下服务器端方法,我正试图通过jQuery使用AJAX调用它 [WebMethod] public static IEnumerable<Message> GetAllMessages(int officerId) { SIBSv2Entities db = new SIBSv2Entities(); return (from m in db.

和其他一些人一样,我在序列化实体框架对象时遇到了问题,因此我无法通过AJAX以JSON格式发送数据

我有以下服务器端方法,我正试图通过jQuery使用AJAX调用它

[WebMethod]
public static IEnumerable<Message> GetAllMessages(int officerId)
{

        SIBSv2Entities db = new SIBSv2Entities();

        return  (from m in db.MessageRecipients
                        where m.OfficerId == officerId
                        select m.Message).AsEnumerable<Message>();
}
这是因为实体框架创建循环引用的方式,以保持所有对象在服务器端的相关性和可访问性

我在()中遇到了以下代码,它声称通过限制引用的最大深度来解决这个问题。我已经添加了下面的代码,因为我必须稍微调整它以使其工作(网站上的代码中缺少所有的尖括号)

使用System.Web.Script.Serialization;
使用System.Collections.Generic;
使用系统集合;
使用System.Linq;
使用制度;
公共类eObjectConverter:JavaScriptConverter
{
私有int_currentDepth=1;
私有只读int_maxDepth=2;
私有只读列表_processedObjects=new List();
私有只读类型[]\内置类型=新[]{
类型(bool),
类型(字节),
类型(sbyte),
类型(字符),
类型(十进制),
类型(双),
类型(浮动),
类型(int),
类型(uint),
类型(长),
类型(ulong),
类型(短),
类型(ushort),
类型(字符串),
类型(日期时间),
类型(Guid)
};
公共EFObjectConverter(int maxDepth=2,
EFObjectConverter父级=null)
{
_maxDepth=maxDepth;
如果(父项!=null)
{
_currentDepth+=父级。\u currentDepth;
}
}
公共重写对象反序列化(IDictionary dictionary、类型、JavaScriptSerializer序列化程序)
{
返回null;
}     
公共重写IDictionary序列化(对象obj、JavaScriptSerializer序列化程序)
{
_processedObjects.Add(obj.GetHashCode());
Type Type=obj.GetType();
var properties=来自type.GetProperties()中的p
p.可以在哪里写作&&
p、 能写&&
_builtInTypes.Contains(p.PropertyType)
选择p;
var result=properties.ToDictionary(
property=>property.Name,
property=>(对象)(property.GetValue(obj,null)
==零
? ""
:property.GetValue(obj,null).ToString().Trim())
);
如果(\u maxDepth>=\u currentDepth)
{
var complexProperties=来自type.GetProperties()中的p
p.可以在哪里写作&&
p、 通读&&
!\u内置类型。包含(p.PropertyType)&&
!\u processedObjects.Contains(p.GetValue(obj,null)
==零
? 0
:p.GetValue(obj,null).GetHashCode())
选择p;
foreach(ComplexProperty中的var属性)
{
var js=新的JavaScriptSerializer();
RegisterConverters(新列表{new EFObjectConverter(_maxDepth-_currentDepth,this)});
Add(property.Name,js.Serialize(property.GetValue(obj,null));
}
}
返回结果;
}
公共覆盖IEnumerable SupportedTypes
{
得到
{
返回GetType().Assembly.GetTypes();
}
}
}
但是,即使在使用该代码时,也应以以下方式:

    var js = new System.Web.Script.Serialization.JavaScriptSerializer();
    js.RegisterConverters(new List<System.Web.Script.Serialization.JavaScriptConverter> { new EFObjectConverter(2) });
    return js.Serialize(messages);
var js=new System.Web.Script.Serialization.JavaScriptSerializer();
js.RegisterConverters(新列表{new EFObjectConverter(2)});
返回js.Serialize(消息);

我仍然看到
检测到循环引用…
异常被抛出

我刚刚成功地测试了这段代码

在您的情况下,消息对象可能位于不同的程序集中?被重写的属性
SupportedTypes
仅返回其自身程序集中的所有内容,因此当调用serialize时,
JavaScriptSerializer
默认为标准的
JavaScriptConverter


您应该能够验证此调试

发生错误的原因是EF为某些具有1:1关系的实体生成了一些“引用”类,并且JavaScriptSerializer未能序列化。 我使用了一种变通方法,添加了一个新条件:

    !p.Name.EndsWith("Reference")
获取复杂属性的代码如下所示:

    var complexProperties = from p in type.GetProperties()
                                    where p.CanWrite &&
                                          p.CanRead &&
                                          !p.Name.EndsWith("Reference") &&
                                          !_builtInTypes.Contains(p.PropertyType) &&
                                          !_processedObjects.Contains(p.GetValue(obj, null)
                                            == null
                                            ? 0
                                            : p.GetValue(obj, null).GetHashCode())
                                    select p;

希望这对您有所帮助。

您还可以从上下文中分离该对象,它将删除导航属性,以便对其进行序列化。对于与Json一起使用的数据存储库类,我使用如下内容

 public DataModel.Page GetPage(Guid idPage, bool detach = false)
    {
        var results = from p in DataContext.Pages
                      where p.idPage == idPage
                      select p;

        if (results.Count() == 0)
            return null;
        else
        {
            var result = results.First();
            if (detach)
                DataContext.Detach(result);
            return result;
        }
    }
默认情况下,返回的对象将具有所有复杂/导航属性,但通过设置detach=true,它将删除这些属性并仅返回基本对象。对于对象列表,实现如下所示

 public List<DataModel.Page> GetPageList(Guid idSite, bool detach = false)
    {
        var results = from p in DataContext.Pages
                      where p.idSite == idSite
                      select p;

        if (results.Count() > 0)
        {
            if (detach)
            {
                List<DataModel.Page> retValue = new List<DataModel.Page>();
                foreach (var result in results)
                {
                    DataContext.Detach(result);
                    retValue.Add(result);
                }
                return retValue;
            }
            else
                return results.ToList();

        }
        else
            return new List<DataModel.Page>();
    }
公共列表GetPageList(Guid idSite,bool detach=false) { var results=来自DataContext.Pages中的p 其中p.idSite==idSite 选择p; 如果(results.Count()>0) { 如果(分离) { List retValue=新列表(); foreach(结果中的var结果) { DataContext.Detach(结果); retValue.Add(结果); } 返回值; } 其他的 返回结果。ToList(); } 其他的 返回新列表(); }
我在通过Ajax将视图推送到UI组件时遇到了类似的问题

我还找到并尝试使用您提供的代码示例。我对该代码有一些问题:

  • SupportedTypes
    没有获取我需要的类型,因此转换器
     public DataModel.Page GetPage(Guid idPage, bool detach = false)
        {
            var results = from p in DataContext.Pages
                          where p.idPage == idPage
                          select p;
    
            if (results.Count() == 0)
                return null;
            else
            {
                var result = results.First();
                if (detach)
                    DataContext.Detach(result);
                return result;
            }
        }
    
     public List<DataModel.Page> GetPageList(Guid idSite, bool detach = false)
        {
            var results = from p in DataContext.Pages
                          where p.idSite == idSite
                          select p;
    
            if (results.Count() > 0)
            {
                if (detach)
                {
                    List<DataModel.Page> retValue = new List<DataModel.Page>();
                    foreach (var result in results)
                    {
                        DataContext.Detach(result);
                        retValue.Add(result);
                    }
                    return retValue;
                }
                else
                    return results.ToList();
    
            }
            else
                return new List<DataModel.Page>();
        }
    
    public class EFJavaScriptSerializer : JavaScriptSerializer
      {
        public EFJavaScriptSerializer()
        {
          RegisterConverters(new List<JavaScriptConverter>{new EFJavaScriptConverter()});
        }
      }
    
    public class EFJavaScriptConverter : JavaScriptConverter
      {
        private int _currentDepth = 1;
        private readonly int _maxDepth = 1;
    
        private readonly List<object> _processedObjects = new List<object>();
    
        private readonly Type[] _builtInTypes = new[]
        {
          typeof(int?),
          typeof(double?),
          typeof(bool?),
          typeof(bool),
          typeof(byte),
          typeof(sbyte),
          typeof(char),
          typeof(decimal),
          typeof(double),
          typeof(float),
          typeof(int),
          typeof(uint),
          typeof(long),
          typeof(ulong),
          typeof(short),
          typeof(ushort),
          typeof(string),
          typeof(DateTime),
          typeof(DateTime?),
          typeof(Guid)
      };
        public EFJavaScriptConverter() : this(1, null) { }
    
        public EFJavaScriptConverter(int maxDepth = 1, EFJavaScriptConverter parent = null)
        {
          _maxDepth = maxDepth;
          if (parent != null)
          {
            _currentDepth += parent._currentDepth;
          }
        }
    
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
          return null;
        }
    
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
          _processedObjects.Add(obj.GetHashCode());
          var type = obj.GetType();
    
          var properties = from p in type.GetProperties()
                           where p.CanRead && p.GetIndexParameters().Count() == 0 &&
                                 _builtInTypes.Contains(p.PropertyType)
                           select p;
    
          var result = properties.ToDictionary(
                        p => p.Name,
                        p => (Object)TryGetStringValue(p, obj));
    
          if (_maxDepth >= _currentDepth)
          {
            var complexProperties = from p in type.GetProperties()
                                    where p.CanRead &&
                                          p.GetIndexParameters().Count() == 0 &&
                                          !_builtInTypes.Contains(p.PropertyType) &&
                                          p.Name != "RelationshipManager" &&
                                          !AllreadyAdded(p, obj)
                                    select p;
    
            foreach (var property in complexProperties)
            {
              var complexValue = TryGetValue(property, obj);
    
              if(complexValue != null)
              {
                var js = new EFJavaScriptConverter(_maxDepth - _currentDepth, this);
    
                result.Add(property.Name, js.Serialize(complexValue, new EFJavaScriptSerializer()));
              }
            }
          }
    
          return result;
        }
    
        private bool AllreadyAdded(PropertyInfo p, object obj)
        {
          var val = TryGetValue(p, obj);
          return _processedObjects.Contains(val == null ? 0 : val.GetHashCode());
        }
    
        private static object TryGetValue(PropertyInfo p, object obj)
        {
          var parameters = p.GetIndexParameters();
          if (parameters.Length == 0)
          {
            return p.GetValue(obj, null);
          }
          else
          {
            //cant serialize these
            return null;
          }
        }
    
        private static object TryGetStringValue(PropertyInfo p, object obj)
        {
          if (p.GetIndexParameters().Length == 0)
          {
            var val = p.GetValue(obj, null);
            return val;
          }
          else
          {
            return string.Empty;
          }
        }
    
        public override IEnumerable<Type> SupportedTypes
        {
          get
          {
            var types = new List<Type>();
    
            //ef types
            types.AddRange(Assembly.GetAssembly(typeof(DbContext)).GetTypes());
            //model types
            types.AddRange(Assembly.GetAssembly(typeof(BaseViewModel)).GetTypes());
    
    
            return types;
    
          }
        }
      }
    
    [Grid]
    public ActionResult _GetOrders(int id)
    { 
       return new GridModel(Service.GetOrders(id));
    }
    
    public class GridAttribute : GridActionAttribute, IActionFilter
      {    
        /// <summary>
        /// Determines the depth that the serializer will traverse
        /// </summary>
        public int SerializationDepth { get; set; } 
    
        /// <summary>
        /// Initializes a new instance of the <see cref="GridActionAttribute"/> class.
        /// </summary>
        public GridAttribute()
          : base()
        {
          ActionParameterName = "command";
          SerializationDepth = 1;
        }
    
        protected override ActionResult CreateActionResult(object model)
        {    
          return new EFJsonResult
          {
           Data = model,
           JsonRequestBehavior = JsonRequestBehavior.AllowGet,
           MaxSerializationDepth = SerializationDepth
          };
        }
    }
    
    public class EFJsonResult : JsonResult
      {
        const string JsonRequest_GetNotAllowed = "This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.";
    
        public EFJsonResult()
        {
          MaxJsonLength = 1024000000;
          RecursionLimit = 10;
          MaxSerializationDepth = 1;
        }
    
        public int MaxJsonLength { get; set; }
        public int RecursionLimit { get; set; }
        public int MaxSerializationDepth { get; set; }
    
        public override void ExecuteResult(ControllerContext context)
        {
          if (context == null)
          {
            throw new ArgumentNullException("context");
          }
    
          if (JsonRequestBehavior == JsonRequestBehavior.DenyGet &&
              String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
          {
            throw new InvalidOperationException(JsonRequest_GetNotAllowed);
          }
    
          var response = context.HttpContext.Response;
    
          if (!String.IsNullOrEmpty(ContentType))
          {
            response.ContentType = ContentType;
          }
          else
          {
            response.ContentType = "application/json";
          }
    
          if (ContentEncoding != null)
          {
            response.ContentEncoding = ContentEncoding;
          }
    
          if (Data != null)
          {
            var serializer = new JavaScriptSerializer
            {
              MaxJsonLength = MaxJsonLength,
              RecursionLimit = RecursionLimit
            };
    
            serializer.RegisterConverters(new List<JavaScriptConverter> { new EFJsonConverter(MaxSerializationDepth) });
    
            response.Write(serializer.Serialize(Data));
          }
        }