programing

Json 및 순환 참조 예외

topblog 2023. 3. 4. 14:06
반응형

Json 및 순환 참조 예외

나는 다른 물체를 원형으로 참조하는 물체를 가지고 있다.이러한 오브젝트 간의 관계를 고려할 때 이것이 올바른 설계입니다.

일러스트에 대해서

Machine => Customer => Machine

예상대로 Json을 사용하여 머신 또는 고객 오브젝트를 시리얼화하려고 하면 문제가 발생합니다.머신과 고객 오브젝트의 관계를 끊고 싶지 않기 때문에 이 문제를 어떻게 해결해야 할지 잘 모르겠습니다.이 문제를 해결하기 위한 옵션은 무엇입니까?

편집

현재 Controller base 클래스에서 제공하는 Json 메서드를 사용하고 있습니다.즉, 제가 하고 있는 시리얼화는 다음과 같은 기본적인 것입니다.

Json(machineForm);

업데이트:

'우리'는하지 마세요.NonSerializedAttribute,JavaScriptSerializer무시한 것 같아요

''를 합니다.ScriptIgnoreAttributeSystem.Web.Script.Serialization.

public class Machine
{
    public string Customer { get; set; }

    // Other members
    // ...
}

public class Customer
{
    [ScriptIgnore]
    public Machine Machine { get; set; }    // Parent reference?

    // Other members
    // ...
}

때 던질 때 던질 때 던질 때 던질 때MachineJson, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴMachine로로 합니다.Customer 않는다.Customer로로 합니다.Machine.

는 아직 대로 할 수 , 그 는 " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""JavaScriptSerializer(가)Jsonmethod합니다.

구글의 "json.encode circular reference"에 대한 세 번째 결과(현재)이기 때문에 이 답변에 대해 답변합니다.또한 위의 답변(완전히)에는 동의하지 않습니다만, ScriptIgnoreAttribute를 사용하면 JSON의 다른 방향의 관계를 건너고 싶지 않다는 것을 전제로 하고 있습니다.한 가지 사용 사례 때문에 귀사의 모델을 잠그는 것은 믿지 않습니다.

이 간단한 해결책을 사용하는 것은 나에게 영감을 주었다.

MVC의 뷰에서 작업 중이기 때문에 모델이 있고 모델을 ViewData에 할당하기만 하면 됩니다.컨트롤러 내에서 모델을 만들고 View 내에서 LINQ 쿼리를 사용하여 다음과 같이 특정 JSON에 대해 문제가 되는 순환 참조를 제거하여 데이터를 적절히 평탄화합니다.

var jsonMachines = from m in machineForm
                   select new { m.X, m.Y, // other Machine properties you desire
                                Customer = new { m.Customer.Id, m.Customer.Name, // other Customer properties you desire
                              }};
return Json(jsonMachines);

또는 기계 -> 고객과의 관계가 1인 경우.* -> * 그럼, 다음의 조작을 실시합니다.

var jsonMachines = from m in machineForm
                   select new { m.X, m.Y, // other machine properties you desire
                                Customers = new List<Customer>(
                                               (from c in m.Customers
                                                select new Customer()
                                                {
                                                   Id = c.Id,
                                                   Name = c.Name,
                                                   // Other Customer properties you desire
                                                }).Cast<Customer>())
                               };
return Json(jsonMachines);

txl의 응답에 따라 느린 로드 및 프록시 생성을 비활성화해야 하며 일반 방법을 사용하여 데이터를 가져올 수 있습니다.

예:

//Retrieve Items with Json:
public JsonResult Search(string id = "")
{
    db.Configuration.LazyLoadingEnabled = false;
    db.Configuration.ProxyCreationEnabled = false;

    var res = db.Table.Where(a => a.Name.Contains(id)).Take(8);

    return Json(res, JsonRequestBehavior.AllowGet);
}

같은 문제를 안고 있을 때 사용합니다.L2E 오브젝트를 IDirectionary로 "평탄화"하는 간단한 확장 메서드를 만들었습니다.IDictionary는 JavaScriptSerializer에 의해 올바르게 시리얼화됩니다.결과 Json은 개체를 직접 직렬화하는 것과 동일합니다.

시리얼라이제이션의 레벨을 제한하기 때문에 순환 참조는 회피됩니다.또한 1->n개의 링크된 테이블(엔티티 세트)도 포함되지 않습니다.

    private static IDictionary<string, object> JsonFlatten(object data, int maxLevel, int currLevel) {
        var result = new Dictionary<string, object>();
        var myType = data.GetType();
        var myAssembly = myType.Assembly;
        var props = myType.GetProperties();
        foreach (var prop in props) {
            // Remove EntityKey etc.
            if (prop.Name.StartsWith("Entity")) {
                continue;
            }
            if (prop.Name.EndsWith("Reference")) {
                continue;
            }
            // Do not include lookups to linked tables
            Type typeOfProp = prop.PropertyType;
            if (typeOfProp.Name.StartsWith("EntityCollection")) {
                continue;
            }
            // If the type is from my assembly == custom type
            // include it, but flattened
            if (typeOfProp.Assembly == myAssembly) {
                if (currLevel < maxLevel) {
                    result.Add(prop.Name, JsonFlatten(prop.GetValue(data, null), maxLevel, currLevel + 1));
                }
            } else {
                result.Add(prop.Name, prop.GetValue(data, null));
            }
        }

        return result;
    }
    public static IDictionary<string, object> JsonFlatten(this Controller controller, object data, int maxLevel = 2) {
        return JsonFlatten(data, maxLevel, 1);
    }

My Action 메서드는 다음과 같습니다.

    public JsonResult AsJson(int id) {
        var data = Find(id);
        var result = this.JsonFlatten(data);
        return Json(result, JsonRequestBehavior.AllowGet);
    }

Entity Framework 버전4 에서는, 다음의 옵션을 사용할 수 있습니다.Object Context Options(오브젝트 컨텍스트 옵션)Lazy Loading Enabled(레이지 로드 활성화)

이 값을 false로 설정하면 '순환 참조' 문제를 방지할 수 있습니다.그러나 포함할 네비게이션 속성을 명시적으로 로드해야 합니다.

참조: http://msdn.microsoft.com/en-us/library/bb896272.aspx

내가 알기로는 오브젝트 참조를 시리얼화할 수는 없지만 다음과 같은 더러운 해킹을 사용할 수 있는 것은 복사본뿐이기 때문입니다.

  1. 고객은 머신 참조를 머신의 ID로 시리얼화해야 합니다.
  2. json 코드를 역직렬화하면 그 위에서 해당 ID를 적절한 참조로 변환하는 단순한 함수를 실행할 수 있습니다.

어떤 것이 루트 개체인지 결정해야 합니다.머신이 루트라고 하면 고객은 머신의 서브 오브젝트입니다.머신을 시리얼화하면 JSON에서 서브오브젝트로 고객을 시리얼화하며, 고객이 시리얼화되면 머신에 대한 백레퍼런스는 시리얼화되지 않습니다.코드가 기계를 역직렬화하면 기계의 고객 서브오브젝트를 역직렬화하고 고객으로부터 기계에 대한 백레퍼런스를 복구합니다.

대부분의 시리얼라이제이션라이브러리는 클래스별로 역직렬화가 실행되는 방법을 수정하기 위한 일종의 후크를 제공합니다.이 후크를 사용하여 머신클래스의 역직렬화를 수정하여 머신고객의 백레퍼런스를 복원해야 합니다.이 훅의 정확한 용도는 사용 중인 JSON 라이브러리에 따라 달라집니다.

같은 할 수 은, 「어나니머스 타입」을하는 인터페이스를 가 있었기 때문입니다.또한 어나니머스 타입을 사용할 수 없었습니다.그 이유는 인터페이스를 실장할 필요가 있었기 때문입니다.List<MyType>모든 본 , 이 도표는 항해성과의 모든 관계를 나타내는 으로 나타났습니다.MyType MyObject둘 다 서로를 살렸기 때문에 순환 참조를 하게 된 거죠

「 」라고 MyObjectMyType그 결과 이 문제는 단방향 관계로 해결되었습니다.

제가 한 일은 조금 과격하지만, 그 속성은 필요 없기 때문에, 순환 참조를 일으키는 끔찍한 오류를 일으키고 있기 때문에, 연재하기 전에 null로 설정했습니다.

SessionTickets result = GetTicketsSession();
foreach(var r in result.Tickets)
{
    r.TicketTypes = null; //those two were creating the problem
    r.SelectedTicketType = null;
}
return Json(result);

속성이 필요한 경우 원형 참조를 보유하지 않고 중요한 요소의 ID를 유지하는 뷰 모델을 작성할 수 있습니다.이러한 뷰 모델은 나중에 원래 값을 복원하는 데 사용할 수 있습니다.

언급URL : https://stackoverflow.com/questions/2002940/json-and-circular-reference-exception

반응형