programing

개체를 JSON으로 직렬화하는 동안 순환 참조 예외가 감지되었습니다.

newnotes 2023. 3. 21. 22:32
반응형

개체를 JSON으로 직렬화하는 동안 순환 참조 예외가 감지되었습니다.

이 투고에서 설명한 바와 같이 엔티티 프레임워크 프록시를 시리얼화하는 동안 Json 시리얼화 오류가 발생합니다.

'System' 유형의 개체를 직렬화하는 동안 순환 참조가 탐지되었습니다.Data. 엔티티Dynamic Proxies.PurchaseOrder_446B939192F161CDBC740067F174F7A6059B0F9C0EEE68CD3EBBD63CF9AF5BD0'입니다.

다만, 다른 점은, 제 사업체에는 순환 참조가 없고, 실가동 환경에서만 발생합니다.현지에서는 모든 것이 잘 작동한다...

마이 엔티티:

public interface IEntity
{
    Guid UniqueId { get; }
    int Id { get; }
} 

public class Entity : IEntity
{
    public int Id { get; set; }
    public Guid UniqueId { get; set; }
}

public class PurchaseOrder : Entity
{
    public string Username { get; set; }
    public string Company { get; set; }

    public string SupplierId { get; set; }
    public string SupplierName { get; set; }

    public virtual ICollection<PurchaseOrderLine> Lines { get; set; }
}

public class PurchaseOrderLine : Entity
{
    public string Code { get; set; }
    public string Name { get; set; }
    public decimal Quantity { get; set; }
}

예외를 발생시키는 PurchaseOrderController에 대한 GetCurrent 액션:

public class PurchaseOrderController : Controller
{
    private readonly IUnitOfWork _unitOfWork;

    public PurchaseOrderController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    public JsonResult GetCurrent()
    {
        return Json(EnsurePurchaseOrder(), JsonRequestBehavior.AllowGet);
    }

    private PurchaseOrder EnsurePurchaseOrder()
    {
        var company = RouteData.GetRequiredString("company");
        var repository = _unitOfWork.GetRepository<PurchaseOrder>();

        var purchaseOrder = repository
                .Include(p => p.Lines)
                .FirstOrDefault
                (
                    p => p.Company == company && 
                         p.Username == User.Identity.Name
                );

        if (purchaseOrder == null)
        {
            purchaseOrder = repository.Create();
            purchaseOrder.UniqueId = Guid.NewGuid();
            purchaseOrder.Company = company;
            purchaseOrder.Username = User.Identity.Name;
            _unitOfWork.SaveChanges();
        }

        return purchaseOrder;
    }
}

옵션 1(권장)

DbContext에서 프록시 오브젝트 작성을 해제해 보십시오.

DbContext.Configuration.ProxyCreationEnabled = false;

통상, 이 시나리오는 애플리케이션이 POCO 오브젝트(T4 Generated 또는 Code-First)를 사용하고 있기 때문입니다.이 문제는 엔티티 프레임워크가 POCO 객체에 내장되지 않은 객체의 변경을 추적하려고 할 때 발생합니다.이 문제를 해결하기 위해 EF는 POCO 개체에 속성이 없고 직렬화할 수 없는 프록시 개체를 만듭니다.

이 방법을 권장하는 이유는 웹 사이트를 사용하면 Entity Framework 개체에 대한 변경 추적(스테이트풀)이 필요하지 않을 수 있기 때문입니다. 변경 추적이 비활성화되어 모든 개체에서 동일한 방식으로 일관되게 작동하기 때문에 메모리와 CPU를 사용할 수 있습니다.

옵션 2

시리얼라이저(JSON 등)를 사용합니다.ASP에 이미 포함되어 있는 네트워크입니다.Net 4). 커스터마이즈가 오브젝트를 시리얼화할 수 있도록 합니다.

이 접근방식을 권장하지 않는 이유는 최종적으로는 커스텀오브젝트 시리얼라이제이션로직이다른오브젝트타입으로시리얼프록시에필요하기때문입니다.이는 결과를 다운스트림으로 전달하기 위해 논리에 의존한다는 것을 의미합니다.오브젝트 변경은 ASP 내에서 로직을 변경하는 것을 의미합니다.Net MVC 프로젝트(모든 버전)는 보기만 변경하는 것이 아니라 로직을 처음 작성한 사용자 외에는 쉽게 알 수 없는 변경 사항이 있습니다.

옵션 3(Entity Framework 5.x +)

특정 쿼리에서 프록시 개체를 비활성화하려면 .AsNoTracking()을 사용합니다.변경 추적을 사용해야 하는 경우 솔루션 #1에 적합한 중간 솔루션을 사용할 수 있습니다.

POCO를 사용하다문제는 EF 런타임에 의해 생성되는 동적 프록시가 일반적으로 그렇지 않다는 것입니다. 설정할 수 요.context.Configuration.ProxyCreationEnabled로로 합니다.false게으른 로딩이 없어집니다.은 가가 my my my my my my my my my my를 사용하는 것입니다.Json.NETEF에 의한 것입니다.

ADO.NET Entity Framework 지원이 Json에 잘못 추가되었습니다.그물

에 널리 사용되는 고성능 JSON 프레임워크.그물

저는 웹에 흩어져 있는 다음과 같은 다양한 솔루션을 모두 시도해 보려고 수없이 많은 시간을 보냈습니다.

  • [Json Ignore]
  • 내부 게터
  • LazyLoadingEnabled 및 ProxyCreationEnabled의 디세이블화
  • ReferenceLoopHandling을 "무시"로 설정
  • 필요한 경우 명시적 로드를 신중하게 사용

그 모든 것이 결국 내게는 결실을 맺지 못했다.재산을 무시하면 한 명의 질의는 도움이 되지만 다른 세 명은 피해를 입힙니다.그것은 마치 두들겨 패는 것과 같은 프로그래밍 같은 느낌이었다.

문제의 배경은 어플리케이션에서 전송되는 데이터가 JSON이어야 한다는 것이었습니다.어쩔 수 없어요.삽입 및 업데이트는 분명히 문제를 훨씬 덜 일으킵니다.그러나 정규화된 데이터베이스(버전 내역 포함)에 저장된 데이터를 직렬화하도록 선택하는 것은 악몽입니다.

해결 방법:

필요한 데이터(속성)를 익명 개체로 반환합니다.

코드 예:

이 경우 '날짜 예약'에 따라 최신 티켓 3장이 필요했습니다.그러나 관련 엔티티에 여러 개의 속성을 저장해야 했습니다.

var tickets =
     context.TicketDetails
    .Where(t => t.DateScheduled >= DateTime.Now)
    .OrderBy(t => t.DateScheduled)
    .Take(3)
    .Include(t => t.Ticket)
    .Include(t => t.Ticket.Feature)
    .Include(t => t.Ticket.Feature.Property)
    .AsEnumerable()
    .Select(
        t =>
        new {
            ID = t.Ticket.ID,
            Address = t.Ticket.Feature.Property.Address,
            Subject = t.Ticket.Subject,
            DateScheduled = String.Format("{0:MMMM dd, yyyy}", t.DateScheduled)
    }
);

자기 참조 루프도 없고

엔티티와 오브젝트가 변경될 수 있기 때문에 이 상황이 모든 경우에 적절하지는 않을 수 있다는 것을 알고 있습니다.하지만 다른 모든 것이 실패한다면 확실히 고려할 가치가 있다.

다른 클래스에 대한 참조가 있는 클래스는 다음과 같이 속성을 추가합니다.

[Newtonsoft.Json.JsonIgnoreAttribute]
public virtual ICollection<PurchaseOrderLine> Lines { get; set; }

이제 모든 것이 원활히 작동한다.

저도 같은 문제가 있었습니다만, 저는 보기 위해 필요한 컬럼만 통과했습니다.2개뿐입니다.

 List<SubCategory> lstSubCategory = GetSubCateroy() // list from repo

 var subCategoryToReturn = lstSubCategory.Select(S => new { Id  = S.Id, Name = S.Name }); 

return this.Json(subCategoryToReturn , JsonRequestBehavior.AllowGet);

같은 에러가 있었지만, 프로덕션 서버와 로컬에서 모두 확인되었습니다.DbContext 구성을 변경해도 문제가 해결되지 않았습니다.다른 해결책이 제시되었습니다.

[IgnoreDataMember]

DB 엔티티 참조의 속성.이것이 당신의 문제와 더 관련이 있을 것 같다면 여기 있는 게시물을 참조하십시오.

ASP.NET Web API 시리얼라이즈드 JSON 오류: "Self Referencing loop"

고객님의 고객명DbContextclass, 다음 코드 행을 추가합니다.

this.Configuration.ProxyCreationEnabled = false;

예를 들어 다음과 같습니다.

public partial class EmpDBEntities : DbContext
{
    public EmpDBEntities()
        : base("name=EmpDBEntities")
    {
        this.Configuration.ProxyCreationEnabled = false;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        throw new UnintentionalCodeFirstException();
    }

    public virtual DbSet<Department> Departments { get; set; }
    public virtual DbSet<Employee> Employees { get; set; }
}

순환 참조는 개체에 빠른 로드를 사용하기 때문에 발생합니다.

3가지 방법이 있습니다.

  • Query(linq 또는 lamda) DbContext를 로드할 때는 빠른 로드를 해제하십시오.배열.ProxyCreationEnabled = false;
  • 개체 분리(= 빠른 로드 기능 및 프록시 없음)
    • 저장소.분리(엔티티 오브젝트)
    • [ DbContext 。엔트리(entityObject)EntityState = EntityState.떨어져 있다
  • 속성 복제
    • AutoMapper와 같은 것을 사용하여 개체를 복제할 수 있습니다. ICloneable 인터페이스를 사용하지 마십시오. 이 인터페이스는 개체의 ProxyProperties도 복제하기 때문에 작동하지 않습니다.
  • API를 구축하는 경우 다른 구성(프록시를 반환하지 않음)으로 separte 프로젝트를 사용해 보십시오.

추신. 프록시는 엔티티 프레임워크에서 로드할 때 EF에 의해 생성되는 객체입니다.요컨대:즉, 원래 값과 업데이트된 값이 유지되므로 나중에 업데이트할 수 있습니다.다른 작업을 처리합니다;-)

저도 같은 문제가 있어서 Json의 체크를 해제하고 해결했습니다.참조 관리자의 프로젝트 확장에서 NET을 선택합니다.

(이미지 http://i.stack.imgur.com/RqbXZ.png) 참조).

또한 새로운 버전의 올바른 경로를 매핑하기 위해 project.csproj 파일을 변경해야 했습니다.

<Reference Include="Newtonsoft.Json">
  <HintPath>..\packages\Newtonsoft.Json.6.0.5\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>

web.config를 설정할 필요가 있었습니다.

  <dependentAssembly>
    <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
    <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
  </dependentAssembly>

web.config 파일에서는 설치된 버전이 6.0.5임에도 불구하고 강제로 이전 버전(6.0.0)을 참조하도록 되어 있습니다.

도움이 됐으면 좋겠다!

언급URL : https://stackoverflow.com/questions/16949520/circular-reference-detected-exception-while-serializing-object-to-json

반응형