Search code examples
many-to-manyentity-framework-5fluent-interfacecascading-deletes

Many-to-Many Relations with 'code first' in Entity Framework 5 (EF5 - final release) wtih VS2012


I had invest now one day to find a solution wihtout success.

I like to create a simple Many to Many relation.

For that I've created two Models:

A Player class where i will have the 'Turnaments' navigation property to see which turnaments has visit a player.

public class Player
{
    [Key]
    public Int64 PlayerId { get; set; }

    public string FirstName { get; set; }

    [Required]
    public string Surename { get; set; }

    public virtual ICollection<Turnament> Turnaments { get; set; }
}

and a Turnament class where I will have the 'Players' navigation property to see which players a part of the turnament.

public class Turnament
{
    [Key]
    public int TurnamentId { get; set; }

    [Required]
    public string Name { get; set; }

    public DateTime? StartDate { get; set; }

    public DateTime? EndDate { get; set; }

    public bool IsClosed { get; set; }

    public virtual ICollection<Player> Players { get; set; }
}

If start the mirgation of by the command 'upate-database' (automtic migratons = on) at the 'Package Manager Console' window of VS2012 - I get the following exception:

Introducing FOREIGN KEY constraint 'FK_dbo.PlayerTurnaments_dbo.Turnaments_Turnament_TurnamentId' on table 'PlayerTurnaments' 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. See previous errors.

Also the Background of that Exception I understand.

So I will reach to tell the entity-framwork that if I'm delete:

a) A Player EF should not push a cascade delete to the associated Turnament

b) A Turnament EF should push a cascade delete to the accociated Player

with that Background the cycles paths are gone.

So I was try to implement a 'Switch cascade delete off' via the fluent-API of Entity Framwork:

public class DataContext : DbContext
{
    public DbSet<Turnament> Turnaments { get; set; }
    public DbSet<Player> Players { get; set; }

    protected override void OnModelCreating( DbModelBuilder modelBuilder )
    {

        //modelBuilder.Entity<Turnament>()
        //    .HasMany( b => b.Players )
        //    .WithMany( a => a.Turnaments )
        //    .Map( m => m.MapLeftKey( "PlayerPid" )
        //                  .MapRightKey( "TurnamentPid" )
        //                  .ToTable( "TurnamentsJoinPlayers" ) );


        //modelBuilder.Entity<Player>().HasRequired( t => t.Turnaments ).
        //    WithMany().WillCascadeOnDelete( false );

        //modelBuilder.Entity<Turnament>().HasRequired( t => t.Players ).
        //    WithMany().WillCascadeOnDelete( false );

        //modelBuilder.Entity<Player>().HasRequired( t => t.TurnamentsRelation ).
        //    WithMany().HasForeignKey( p => p.PlayerId ).WillCascadeOnDelete( false );

        //modelBuilder.Entity<Player>().HasMany(p => p.TurnamentsRelation).

        base.OnModelCreating( modelBuilder );

    }
}

But as you see everthing is commend out because its don't help.

thx for all competent help with more as only some code snippes that only cracks understand :) PS: I'm sure there is a solution for EF5 (final) of that kind of many-to-many relations


Solution

  • SOLUTION

    public class MyAppContext : DbContext
    {
    
       public MyAppContext()
       {
        // Somtimes helps to uncommend that line, then the Database will recreated!
        // (For people that are not fit enough in EF CodeFirst - like me ;)
        // 1) Uncommend 
        // 2) Start Application go on a site that access your data wait for
        //    Exception (No Database!)
        // 3) Unkommend line 
        // 4) Execute 'update-database' at the 'Package Manager Console' of VS 2012
        // Database.SetInitializer(new DropCreateDatabaseAlways<LivescoreContext>());
       }
    
       protected override void OnModelCreating( DbModelBuilder modelBuilder )
       {
            /* Players <-> Turnaments */
            modelBuilder.Entity<Player>()
                .HasMany( p => p.Turnaments )
                .WithMany( p => p.Players )
                .Map( mc =>
                    {
                        mc.MapLeftKey( "PlayerPid" );
                        mc.MapRightKey( "TurnamentPid" );
                        mc.ToTable( "PlayersJoinTurnaments" );
                    } );
    
            base.OnModelCreating( modelBuilder );
       }
    }