关闭

Entity framework serialize POCO to JSON

3463人阅读 评论(0) 收藏 举报

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace Web.Common
{
    /// <summary>
    /// 都是无法序列化JSON序列化 EF的实体对象,
    /// 要么就必须声明什么DataMember??,需要删除实体类的IsRefrence
    /// 太恶心了,网路上找到一个,自己汉化了一下。
    /// </summary>
    public static class JsonHelper
    {
        /// <summary>
        /// 将对象转化为Json字符串
        /// </summary>
        /// <typeparam name="T">源类型</typeparam>
        /// <param name="instance">源类型实例</param>
        /// <returns>Json字符串</returns>
        public static string ToJson(this object obj)
        {
            //string jsonText = JsonConvert.SerializeObject(obj);
            //return jsonText;

            return JsonHelper.JsonSerialize(obj);
        }

        public static string JsonSerialize<T>(T obj) where T : class
        {
            var sb = new StringBuilder("{");

            var parentType = obj.GetType(); // I get type from given object 

            //使用反射来检索该类型的所有属性
            var ms = parentType.GetMembers().Where(v => v.MemberType
                == MemberTypes.Property).ToList<MemberInfo>();

            const string doubleQuote = "\"";
            var counter = 0;
            var stringTypes = new List<String> { "String", "Guid", 
            "Boolean" };

            ///以下类型的使用实体框架。定义忽略的数据类型
            var ignoreEntityTypes = new List<String> { "EntityReference`1", 
            "EntityCollection`1", "EntityState", 
            "EntityKey", "EntitySetName" };

            //开始迭代查找每个属性
            foreach (PropertyInfo p in ms)
            {
                counter++;
                var propertyName = p.Name;
                var propertyType = p.PropertyType;
                var propertyValue = p.GetValue(obj, null);

                //如果属性类型匹配 ignoreTypes,那么进入下一个循环。
                if (ignoreEntityTypes.Contains(propertyType.Name))
                {
                    continue;
                }

                if (stringTypes.Contains(propertyType.Name))
                {
                    if (propertyValue == null)
                    {
                        sb.Append(doubleQuote + propertyName + doubleQuote +
                                  ":" + "null");
                    }

                    else
                    {
                        sb.Append(doubleQuote + propertyName + doubleQuote +
                            ":" + doubleQuote + propertyValue.ToString() + doubleQuote);
                    }
                }

                else if (propertyType != null && propertyType.IsPrimitive)
                {
                    sb.Append(doubleQuote + propertyName + doubleQuote
                        + ":" + propertyValue.ToString());
                }

                //我仍然有疑问如何处理日期和时间,处理日期属性
                else if (propertyType.Name == "DateTime")
                {
                    var dt = (DateTime)propertyValue;
                    sb.Append(doubleQuote + propertyName
                        + doubleQuote + ":"
                        + "new Date(" + dt.Ticks.ToString() + ")");
                }
                else
                {
                    if (propertyValue != null)
                    {
                        sb.Append(doubleQuote + propertyType.Name + doubleQuote + ":");
                        //如果属性值是另一个实体,然后
                        //递归调用的方法。
                        sb.Append(JsonSerialize(propertyValue));
                    }
                    else
                    {
                        continue;
                    }
                }
                //如果不是最后一个属性,然后添加逗号
                if (counter < ms.Count)
                {
                    sb.Append(",");
                }
            }
            sb.Append("}");
            var result = sb.ToString().Replace(",}", "}");
            return result;

        }
    }
}


http://geeks.ms/blogs/fernandezja/archive/2010/05/13/entity-framework-serializar-entidades-con-json-net-error-the-type-entidadxxx-cannot-be-serialized-to-json-because-its-isreference-setting-is-true.aspx


m using Ef 4.1 and I've got a POCO object I'd like to serialize to JSON, I've read there is a problem to do so when using lazy loading but I'm not sure I can because a Message can have a collection ofMessage.

Is there any way to do this? sirialize this kind of object into JSON?

My Message object looks like:

public class Message
{
    [Key]
    public int Id { get; set; }
    public int? ParentId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public DateTime CreatedAt { get; set; }
    public DateTime? LastModified { get; set; }

    public virtual User User { get; set; }

    public virtual Message Parent { get; set; }

    public virtual ICollection<Message> Children { get; set; }
}
link|improve this question

 
feedback

3 Answers

The problem is circular references. An easy way to avoid this is to use Json.Nethttp://james.newtonking.com/projects/json-net.aspx instead of the default MVC json serializer. The latest version of Json.Net will serialize objects with circular references out of the box.http://james.newtonking.com/projects/json/help/PreserveObjectReferences.html for more info on the problem

link|improve this answer
 
Thanks! ReferenceLoopHandling.Ignore and a custom ContractResolver did the trick :-) – CD.. Aug 30 '11 at 6:35
feedback

Eager load it using Include(). Sample linq:

var serializeMe = (from m in MyContext.Message.Include("User") where m.Id == someValue select m).ToList();

That will tell EF to load the User navigation property right away instead of lazy loading it, and the serializer should have no problem with it then.

link|improve this answer
 
Including the related entity solved a problem I was having serializing an EF object graph because I was able to take the virtual keyword off of the offending property in my class. Thanks! – marc Feb 15 at 16:48
feedback

How about this:

  • Mark your class as [Serializable]
  • Use the JsonSerializer to serialize your object to JSON.
  • Perhaps use eager loading on the properties in your EF query?
Message msg = new Message();
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(msg.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, msg);
string json = Encoding.Default.GetString(ms.ToArray());


[Serializable]
public class Message
{
}
link|improve this answer
 
thanks for the detailed answer, but I'm afraid the virtual properties are not loaded this way... – CD.. Aug 29 '11 at 20:51
 
@CD : what am I missing? The virtual property serialized just fine for the collection and the single properties: i.imgur.com/9mkW3.png – p.campbell Aug 29 '11 at 21:03
 
In EF any virtual ICollection will be lazy-loaded.. – CD.. Aug 29 '11 at 21:08
Was this post useful to you?     



0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:964039次
    • 积分:12709
    • 等级:
    • 排名:第1169名
    • 原创:95篇
    • 转载:614篇
    • 译文:12篇
    • 评论:85条
    最新评论