Search code examples
c#entity-frameworkmany-to-many

Circular Reference on entity relationships


My database is code first and I'm stuck on a concept that's preventing me from moving forward with my development.

I have an N to N relationship in three models:

  • TicTacToeTruth can have 1-to-N TicTacToeAction
  • TicTacToeAction can have 1-to-N TicTacToeTruth
  • TicTacToeActionTruths => associative model
builder.HasKey(bA => new { at.TicTacToeTruthId, at.TicTacToeActionId });

builder.HasOne<TicTacToeTruth>(b => b.TicTacToeTruth )
    .WithMany(b => b.TicTacToeActionTruths)
    .HasForeignKey(b => b.TicTacToeTruthId);

builder.HasOne<TicTacToeAction>(a => a.TicTacToeAction)
       .WithMany(a => a.TicTacToeActionTruths )
       .HasForeignKey(a => a.TicTacToeActionId);

The code for my get endpoint from the controller is as follows:

var TruthsWithActions = await _context.TicTacToeTruths
    .Include(bp => bp.TicTacToeActionTruths)
    .ThenInclude(bpa => bpa.TicTacToeAction)
    .ToListAsync();

When I run my code, it loops endlessly. By limiting the results, I'm sure it's building my json tree in a loop.

Do you have any idea how I could load the results without errors? Thanks you in advance for your help !!

In SQL it would look like this

SELECT * 
FROM [dbo].[TicTacToeActionTruths] tr
INNER JOIN [dbo].[TicTacToeActions] act ON act.Id = tr.TicTacToeActionId
INNER JOIN [dbo].[TicTacToeTruths] truth on truth.Id = tr.TicTacToeBodyPartId

I hope to be able to load data, and understand why I'm having this problem.

I've tried to ignore ReferenceLoopHandling so that looping values are excluded from serialization instead of throwing an exception.

builder.Services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

Limiting the depth of results with .Take(3)


Solution

  • I have modified my request for a select as mentioned @StevePy I'm not sure this is best practice, but it works.

    Thank you all for your help. Don't hesitate to react if necessary.

    var truths = await _context.TicTacToeTruths
                .Select(bp => new TicTacToeTruth
                {
                    Id = bp.Id,
                    Name = bp.Name,
    
                    TicTacToeActions = bp.TicTacToeActions.Select(action => new TicTacToeAction
                    {
                        Id = action.Id,
                        Name = action.Name
                    }).ToList()
                })
                .ToListAsync();
    
            return truths;