Entity framework 序列化实体框架问题
和其他一些人一样,我在序列化实体框架对象时遇到了问题,因此我无法通过AJAX以JSON格式发送数据 我有以下服务器端方法,我正试图通过jQuery使用AJAX调用它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.
[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)); } }