Home > Back-end >  C# Web Api rest linq query return too much data
C# Web Api rest linq query return too much data

Time:11-21

Good day, I run into the problem then returning DTO object. I have these classes

public class ProductBase
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public IEnumerable<ProductVariant> Variants { get; set; }
    public int BaseImageId { get; set; } = 0;

}

public class ProductVariant
{
    public int Id { get; set; }
    public int Quantity { get; set; }
    public int ProductBaseId { get; set; }
    public ProductBase productBase { get; set; }
    public int ProductSizeId { get; set; }
    public ProductSize ProductSize { get; set; }
    public int ProductColorId { get; set; }
    public ProductColor ProductColor { get; set; }

    public IEnumerable<ImageVariant> imageVariants { get; set; }
}

public class ProductColor
{
    public int Id { get; set; }
    public string Color { get; set; }
    public IEnumerable<ProductVariant> productVariant { get; set; }
}

public class ProductSize
{
    public int Id { get; set; }
    public string Size { get; set; }

    public IEnumerable<ProductVariant> productVariant { get; set; }
}

In productBaseRepository I have this call

public async Task<IEnumerable<Models.ProductBase>> GetAllWithVariantsAsync()
    {
        var result = await _dataContext.ProductBases
            .Include(pb => pb.Variants)
            .ThenInclude(v => v.ProductSize)
            .Include(pb => pb.Variants)
            .ThenInclude(v => v.ProductColor)
            .ToListAsync();

        return result;
    }

I have created DTO convertion function

public static IEnumerable<ProductBaseDTO> ConvertToDto(this IEnumerable<ProductBase> productBases)
    {
        var returnProductBaseDto = (from product in productBases
                                    select new ProductBaseDTO
                                    {
                                        Id = product.Id,
                                        Name = product.Name,
                                        Variants = product.Variants.ToList(),
                                        Description = product.Description,
                                        BaseImageId = product.BaseImageId,
                                        
                                    }).ToList();
        
        return returnProductBaseDto;
    }

But then I call this function from swagger

 [HttpGet]
    public async Task<ActionResult<List<ProductBaseDTO>>> GetAllProductsWithVariants()
    {
        var baseProductDomain = await _productBaseRepository.GetAllWithVariantsAsync();
        var baseProduct = baseProductDomain.ConvertToDto();
        return Ok(baseProduct);
    }

I get that 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

If I remove variants from call it works, so I need to some how remove Unecessry values from Variants

CodePudding user response:

The problem happens because your ProductVariant references ProductSize and ProductColor and ProductSize and ProductColor reference a list of ProductVariant objects. And ProductVariant has a reference to its BaseProduct. This creates a cycle, two objects referencing each other.

In order to solve this issue, remove productVariant List from ProductSize and ProductColor or remove the ProductSize and ProductColor references from ProductVariant. Also remove the productBase reference from ProductVariant.

Use the IDs to find object references if required instead of having circular object references.

See prevent property from being serialized in web API on how to prevent properties from being serialized without removing the property declaration from the class.

CodePudding user response:

This is because Variants has a reference to its parents type, You could simply set this to null, e.g.

foreach(var x in baseProduct.SelectMany(c => c.Variants) { x.ProductBase = null }

We ussually have different viewmodels to stop these cycles, e.g:

public class Order {
  public List<OrderLine> OrderLines {get;set}
}

public class OrderLine {
  public Order Order {get;set}
}

// Gets mapped to the following viewmodels:

public class OrderViewModel {
  public List<OrderOrderLineViewModel > OrderLines {get;set}
}

public class OrderOrderLineViewModel {
  public Order Order => null; // Stop object cycling
}

Note that the exception message should tell you where the issue is for example $.Variants.productBase.variants.productBase.variants or something similar.

  • Related