Home > other >  ASP.net 6 Object Cycle was detected automapper nested list
ASP.net 6 Object Cycle was detected automapper nested list

Time:01-25

I am currently working on a personal project where I want to map the UserTransaction to GetAllTransactionRes and return all UserTransaction from my database when the API/transaction is hit. Each time I use the API/transaction endpoint I got this error

System.Collections.Generic.List`1[ProjectName.Modules.Transaction.Core.DTO.GetAllTransactionRes]
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
      System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles. Path: $.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.OrderedProducts.UserTransaction.TransactionId.

This is the UserTransaction Entity

    public class UserTransaction
    {
        public int TransactionId { get; set; }
        public DateTime Date { get; set; }

        public virtual ICollection<OrderedProduct> OrderedProducts { get; set; }
    }

This is the Ordered Product Entity

    public class OrderedProduct
    {
        public int Id { get; set; }
        public string Product { get; set; }
        public int ProductId { get; set; }
        public int Quantity { get; set; }
        public bool Returned { get; set; }

        public int TransactionId { get; set; }
        public virtual UserTransaction UserTransaction { get; set; }
    }

This is my mapper. GetAllTransactionRes and AllOrderedProductDTO is the exact copy of UserTransaction and OrderedProduct Entity.

CreateMap<UserTransaction, GetAllTransactionRes>().ForMember(s => s.OrderedProducts, c => c.MapFrom(m => m.OrderedProducts));
CreateMap<OrderedProduct, AllOrderedProductDTO>();

Since I am using MediatR. This is my handler for my GetAllTransactionQuery

        public async Task<ICollection<GetAllTransactionRes>> Handle(GetAllTransactionQuery request, CancellationToken cancellationToken)
        {
            var Transactions = await _context.UserTransactions.Include(ut => ut.OrderedProducts).ToListAsync();
            var mapped = _mapper.Map<ICollection<UserTransaction>, ICollection<GetAllTransactionRes>>(Transactions);
            return mapped;
        }

Before using automapper I used the .include method from efcore which gives me the same error I searched for answers and a person commented in a StackOverflow question that i should not return DB entities directly in my API. This is the question where the said comment is posted

What am I doing wrong? Thanks

CodePudding user response:

The issue is that your AllOrderedProductDTO and your GetAllTransactionRes data transfer objects have a circular reference - transactions contains products which contain the transaction which contains the products...

Here are the DTO classes I would recommend to break out of the cycle:

public class GetAllTransactionRes
{
    public int TransactionId { get; set; }
    public DateTime Date { get; set; }
    // be sure to use the products DTO here and not the entity because the entity has the loop
    public virtual ICollection<AllOrderedProductDTO> OrderedProducts { get; set; }
}

public class AllOrderedProductDTO
{
    public int Id { get; set; }
    public string Product { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; }
    public bool Returned { get; set; }

    public int TransactionId { get; set; }
    // do not include the transaction entity or DTO here so that we avoid the loop
    //public virtual UserTransaction UserTransaction { get; set; }
}
  •  Tags:  
  • Related