0

I'm sure this is simple but can't find an answer probably because I don't know how to word my question.

I'm trying to assign two different Competitors to a single Game as Player and Opponent.

My model classes:

public class Competitor
{
    public int CompetitorId { get; set; }

    // other properties
}

public class Game
{
    public int GameId { get; set; }

    public int PlayerId { get; set; }
    public int OpponentId { get; set; }

    public Competitor Player { get; set; } // This should use PlayerId to return a Competitor
    public Competitor Opponent { get; set; } // This should use OpponentId to return a Competitor
}

I've tried using annotations for ForeignKey and even tried to use Fluent API, but keep getting the same error during Update-Database:

Introducing FOREIGN KEY constraint 'FK_Matches_Competitors_PlayerId' on table 'Matches' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index

Can anyone of you beautiful smart people please slap some sense into me? Thanks

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Joe Hakooz
  • 573
  • 1
  • 5
  • 18
  • 2
    Show us your Fluent EF Model Configuration code. – Dai Mar 21 '23 at 22:35
  • @marc_s... I had read the above article multiple times but it didn't help with my issue. Homie down below's code is a little different and did the trick. – Joe Hakooz Mar 22 '23 at 14:02

1 Answers1

1

You can solve that by registering an entity configuration for either entity, in which you declare which property from that entity is related in what way to the property of the other entity.

In this instance, since I'm guessing Game is more dependant on Comptetitor than vice versa, we'll make a GameConfiguration:

using Domain.Entities;

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace Infrastructure.Data.PostgreSql.Configurations
{
    public class GameConfiguration : IEntityTypeConfiguration<Game>
    {
        public void Configure(EntityTypeBuilder<Game> game)
        {
            game.HasOne(game => game.Player)
                .WithMany()
                .HasForeignKey(game => game.PlayerId)
                .OnDelete(DeleteBehavior.Restrict); // restricts deletion of a Player Competitor participating in this relationship.

            game.HasOne(game => game.Opponent)
                .WithMany()
                .HasForeignKey(game => game.OpponentId)
                .OnDelete(DeleteBehavior.Restrict); // restricts deletion of a Opponent Competitor participating in this relationship.
        }
    }
}

Then in your Context class you apply the configuration during OnModelCreating. You can do that either explicitly for that configuration, or tell the context to find all configuration classes in a given assembly.

using Domain.Entities;

using Infrastructure.Data.PostgreSql.Configurations;

using Microsoft.EntityFrameworkCore;

namespace Infrastructure.Data.PostgreSql
{
    public class DataContext : DbContext
    {
        // Properties
        public DbSet<Competitor> Competitors => Set<Competitor>();
        public DbSet<Game> Games => Set<Game>();

        // Constructors
        public DataContext(DbContextOptions<DataContext> options) : base(options) { }

        // Methods
        protected override void OnModelCreating(ModelBuilder model)
        {
            // Either
            model.ApplyConfiguration(new GameConfiguration());
            // Or
            model.ApplyConfigurationsFromAssembly(typeof(DataContext).Assembly);
        }
    }
}
ErroneousFatality
  • 450
  • 1
  • 5
  • 13