EF在转换成JsonResult时遇到无限循环的解决办法

本博客为作者日常工作遇到的一些问题集合,希望能给热爱编程的初学者一些知识。

基于在应用EF实体类,如果存在导航属性,则return Json(List<Entity> list,JsonRequestBehavior.AllowGet)时会遇到无限循环导致报错的问题,所以希望有办法解决此问题。

解决思路1:

1.新增多一个EF模板,把其导航属性去除。

在.tt模板中,把类名加Model,与原来的类名区分开来。

<#=codeStringGenerator.EntityClassOpening(entity)+"Model"#>
T4模板代码
<#
        foreach (var navigationProperty in navigationProperties)
        {
#>
    <#=codeStringGenerator.NavigationProperty(navigationProperty)#>
<#
        }
#>
去掉这些代码以去除导航属性

 

2.利用一个方法把List<Entity>批量转换成List<EntityModel>。

public class Mapper<T,K> 
    {
        /// <summary>
        /// 把List<T>转换成List<K>
        /// </summary>
        /// <param name="listT"></param>
        /// <param name="model">默认new Model()</param>
        /// <returns></returns>
        public static List<K> MapObjectList(List<T> listT, K model)
        {
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, model); //复制到流中

            List<K> listK = new List<K>();
            foreach (T t in listT)
            {
                ms.Position = 0;
                K k = (K)(bf.Deserialize(ms));

                ObjectMapperManager.DefaultInstance.GetMapper<T, K>().Map(t, k);
                listK.Add(k);
            }
            return listK;
        }
View Code

 

3.可用return Json(List<EntityModel> list,JsonRequestBehavior.AllowGet)

这样把其导航属性去掉,前台就不会出现无线循环的报错了。

 EmitMapper.ObjectMapperManager 可以在nuget里面找到,挺好用的一个类,是用来把EntityA转换成EntityB,把两个实体相同属性的名称

对应赋值。

  但是,这样做效率似乎不高,而且还比较麻烦。于是再找找有没有更便捷的方法,毕竟每次都这样又装箱又拆箱,性能损耗也是不少。于是有了解决思路2

 

解决思路2:

 直接利用方法去除类中的导航属性!!

写一个MyJsonResult类

public class MyJsonResult : JsonResult 
    {
        public JsonSerializerSettings Settings { get; private set; } 

        public MyJsonResult()
        { 
            Settings = new JsonSerializerSettings 
            { 
         //这句是解决问题的关键,也就是json.net官方给出的解决配置选项.                 
          ReferenceLoopHandling = ReferenceLoopHandling.Ignore
            }; 
        }

        public override void ExecuteResult(ControllerContext context) 
        { 
            if (context == null)            
                throw new ArgumentNullException("context"); 
            if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))            
                throw new InvalidOperationException("JSON GET is not allowed"); 
            HttpResponseBase response = context.HttpContext.Response; 
            response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType; 
            if (this.ContentEncoding != null)            
                response.ContentEncoding = this.ContentEncoding; 
            if (this.Data == null)            
                return; 
            var scriptSerializer = JsonSerializer.Create(this.Settings); 
            using (var sw = new StringWriter()) 
            { 
                scriptSerializer.Serialize(sw, this.Data); 
                response.Write(sw.ToString()); 
            } 
        } 
    }

  然后,在BaseController里重写Json方法
public class BaseController : Controller
    {
        protected override JsonResult Json(object data, string contentType, Encoding contentEncoding, JsonRequestBehavior behavior) 
        { 
            return new MyJsonResult 
            { 
                Data = data, 
                ContentType = contentType, 
                ContentEncoding = contentEncoding, 
                JsonRequestBehavior = behavior }; 
        }

    }

  最后只需在Controller里继承BaseController就行了。非常方便!而且没有转换效率的问题。解决思路2是推荐的办法。当然也在解决思路1中学习到了不少的知识。
如果哪位大神有更好的解决办法,请赐教。

 

 

 

 

posted on 2015-11-03 21:08 第29个小强 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/gmxq/p/4921974.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将 InputStream 转换为 JsonResult 对象,需要先将 InputStream 转换为字符串,然后将字符串转换为 JsonResult 对象。可以使用以下代码实现: ``` import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; import java.io.IOException; import java.io.InputStream; import java.util.Scanner; public class InputStreamToJsonResultConverter { public static <T> ResponseEntity<JsonResult<T>> convert(InputStream inputStream, Class<T> clazz) throws IOException { String jsonString = convertInputStreamToString(inputStream); MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); JsonResult<T> jsonResult = converter.getObjectMapper().readValue(jsonString, JsonResult.class); ResponseEntity.BodyBuilder builder = ResponseEntity.status(HttpStatus.valueOf(jsonResult.getStatus())); return builder.body(jsonResult); } private static String convertInputStreamToString(InputStream inputStream) { Scanner scanner = new Scanner(inputStream, "UTF-8"); return scanner.useDelimiter("\\A").next(); } } ``` 这个函数接收两个参数:`inputStream` 是需要转换的 InputStream 对象,`clazz` 是 JsonResult 对象中的 data 字段的类型。该函数返回一个 ResponseEntity<JsonResult<T>> 对象,其中 T 是 data 字段的类型。 你可以将上述代码复制到你的项目中,并根据需要进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值