C# 序列化“SubSonic.Schema .DatabaseColumn”类型的对象时检测到循环引用。

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1153385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 09:29:38  来源:igfitidea点击:

A circular reference was detected while serializing an object of type 'SubSonic.Schema .DatabaseColumn'.

c#.netjsonentity-frameworksubsonic

提问by Jon

I am trying to do a simple JSON return but I am having issues I have the following below.

我正在尝试做一个简单的 JSON 返回,但我遇到了以下问题。

public JsonResult GetEventData()
{
    var data = Event.Find(x => x.ID != 0);
    return Json(data);
}

I get a HTTP 500 with the exception as shown in the title of this question. I also tried

我得到一个 HTTP 500 异常,如这个问题的标题所示。我也试过

var data = Event.All().ToList()

That gave the same problem.

那给了同样的问题。

Is this a bug or my implementation?

这是错误还是我的实现?

采纳答案by Darin Dimitrov

It seems that there are circular references in your object hierarchy which is not supported by the JSON serializer. Do you need all the columns? You could pick up only the properties you need in the view:

您的对象层次结构中似乎存在 JSON 序列化程序不支持的循环引用。你需要所有的列吗?您可以在视图中仅选取您需要的属性:

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

This will make your JSON object lighter and easier to understand. If you have many properties, AutoMappercould be used to automaticallymap between DTO objects and View objects.

这将使您的 JSON 对象更轻巧且更易于理解。如果你有很多属性,AutoMapper可以用来在 DTO 对象和 View 对象之间自动映射。

回答by Marc Gravell

JSON, like xml and various other formats, is a tree-based serialization format. It won't love you if you have circular references in your objects, as the "tree" would be:

JSON 与 xml 和其他各种格式一样,是一种基于树的序列化格式。如果您的对象中有循环引用,它不会爱您,因为“树”将是:

root B => child A => parent B => child A => parent B => ...

There are often ways of disabling navigation along a certain path; for example, with XmlSerializeryou might mark the parent property as XmlIgnore. I don't know if this is possible with the json serializer in question, nor whether DatabaseColumnhas suitable markers (veryunlikely, as it would need to reference every serialization API)

通常有多种方法可以禁用沿特定路径的导航;例如,XmlSerializer您可以将父属性标记为XmlIgnore. 我不知道这是否可能与有关JSON序列,也不是是否DatabaseColumn有合适的标记(非常不可能的,因为这需要参考每个序列化API)

回答by ClayKaboom

This actually happens because the complex objects are what makes the resulting json object fails. And it fails because when the object is mapped it maps the children, which maps their parents, making a circular reference to occur. Json would take infinite time to serialize it, so it prevents the problem with the exception.

这实际上是因为复杂的对象导致生成的 json 对象失败。它失败了,因为当对象被映射时,它映射了孩子,孩子映射了他们的父母,使循环引用发生。Json 将花费无限时间来序列化它,因此它可以防止出现异常问题。

Entity Framework mapping also produces the same behavior, and the solution is to discard all unwanted properties.

实体框架映射也会产生相同的行为,解决方案是丢弃所有不需要的属性。

Just expliciting the final answer, the whole code would be:

只是明确最终答案,整个代码将是:

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           new {
                Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
               }
           , JsonRequestBehavior.AllowGet
           );
}

It could also be the following in case you don't want the objects inside a Resultproperty:

如果您不希望Result属性中的对象,它也可能是以下内容:

public JsonResult getJson()
{
    DataContext db = new DataContext ();

    return this.Json(
           (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
           , JsonRequestBehavior.AllowGet
           );
}

回答by nilesh

Its because of the new DbContext T4 template that is used for generating the EntityFramework entities. In order to be able to perform the change tracking, this templates uses the Proxy pattern, by wrapping your nice POCOs with them. This then causes the issues when serializing with the JavaScriptSerializer.

这是因为用于生成 EntityFramework 实体的新 DbContext T4 模板。为了能够执行更改跟踪,此模板使用代理模式,通过用它们包装您的漂亮 POCO。这会导致在使用 JavaScriptSerializer 进行序列化时出现问题。

So then the 2 solutions are:

那么2个解决方案是:

  1. Either you just serialize and return the properties you need on the client
  2. You may switch off the automatic generation of proxies by setting it on the context's configuration

    context.Configuration.ProxyCreationEnabled = false;

  1. 要么你只是序列化并返回你在客户端上需要的属性
  2. 您可以通过在上下文的配置中设置来关闭代理的自动生成

    context.Configuration.ProxyCreationEnabled = false;

Very well explained in the below article.

在下面的文章中很好地解释了。

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/

回答by Unais.N.I

Avoid converting the table object directly. If relations are set between other tables, it might throw this error. Rather, you can create a model class, assign values to the class object and then serialize it.

避免直接转换表对象。如果在其他表之间设置了关系,则可能会引发此错误。相反,您可以创建一个模型类,为类对象分配值,然后对其进行序列化。

回答by ddfnfal

I had the same problem and solved by using Newtonsoft.Json;

我有同样的问题并解决了 using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});

return Content(list, "application/json");

回答by kravits88

Using Newtonsoft.Json: In your Global.asax Application_Start method add this line:

使用 Newtonsoft.Json:在您的 Global.asax Application_Start 方法中添加以下行:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

回答by A.Kosecik

I'm Using the fix, Because Using Knockout in MVC5 views.

我正在使用修复程序,因为在 MVC5 视图中使用 Knockout。

On action

在行动

return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));

function

功能

   public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
    {
        TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
        foreach (var item in Entity.GetType().GetProperties())
        {
            if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
                item.SetValue(Entity_, Entity.GetPropValue(item.Name));
        }
        return Entity_;  
    }

回答by Ynnoboy

//first: Create a class as your view model

public class EventViewModel 
{
 public int Id{get;set}
 public string Property1{get;set;}
 public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
 var events = await db.Event.Find(x => x.ID != 0);
 List<EventViewModel> model = events.Select(event => new EventViewModel(){
 Id = event.Id,
 Property1 = event.Property1,
 Property1 = event.Property2
}).ToList();
 return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}

回答by Amro

To sum things up, there are 4 solutions to this:

总结起来,有4种解决方案:

Solution 1: turn off ProxyCreation for the DBContext and restore it in the end.

解决方案一:关闭DBContext的ProxyCreation,最后恢复。

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        bool proxyCreation = db.Configuration.ProxyCreationEnabled;
        try
        {
            //set ProxyCreation to false
            db.Configuration.ProxyCreationEnabled = false;

            var data = db.Products.ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
        finally
        {
            //restore ProxyCreation to its original state
            db.Configuration.ProxyCreationEnabled = proxyCreation;
        }
    }

Solution 2: Using JsonConvert by Setting ReferenceLoopHandling to ignore on the serializer settings.

解决方案 2:通过设置 ReferenceLoopHandling 来使用 JsonConvert 以忽略序列化程序设置。

    //using using Newtonsoft.Json;

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.ToList();

            JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);

            return Json(result, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

Following two solutions are the same, but using a model is better because it's strong typed.

以下两个解决方案是相同的,但使用模型更好,因为它是强类型的。

Solution 3: return a Model which includes the needed properties only.

解决方案 3:返回一个仅包含所需属性的模型。

    private DBEntities db = new DBEntities();//dbcontext

    public class ProductModel
    {
        public int Product_ID { get; set;}

        public string Product_Name { get; set;}

        public double Product_Price { get; set;}
    }

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new ProductModel
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }

Solution 4: return a new dynamic object which includes the needed properties only.

解决方案 4:返回一个仅包含所需属性的新动态对象。

    private DBEntities db = new DBEntities();//dbcontext

    public ActionResult Index()
    {
        try
        {
            var data = db.Products.Select(p => new
                                                {
                                                    Product_ID = p.Product_ID,
                                                    Product_Name = p.Product_Name,
                                                    Product_Price = p.Product_Price
                                                }).ToList();

            return Json(data, JsonRequestBehavior.AllowGet);
        }
        catch (Exception ex)
        {
            Response.StatusCode = (int)HttpStatusCode.BadRequest;
            return Json(ex.Message);
        }
    }