Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

ASP.net 6 Object Cycle was detected automapper nested list

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

    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

>Solution :

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; }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading