简体   繁体   中英

How to properly enable EF cascade delete with conventions

I'm using EF 6.4.0 codefirst on a winforms app and Cascade delete is not working

below are my CLASSES

public class PLAYERS_M
{
    [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int PM_ROWID { get; set; }

    public string PM_PLAYER_ID { get; set; }


    public string PM_FULLNAME { get; set; }

    public int? PM_COUNTRY { get; set; }

    public bool PM_IS_HOH  { get; set; }

    public string PM_QUOTE { get; set; }

    public byte[] PM_PHOTO  { get; set; }

    [ForeignKey("PM_COUNTRY")]
    public virtual COUNTRIES COUNTRIES { get; set; }
}

public class COUNTRIES
{
    [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CO_ROWID { get; set; }
    public string CO_CODE { get; set; }
    public string CO_NAME { get; set; }
}

I've added the following method to enable cascade delete on the dbcontext

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
     modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
     modelBuilder.Conventions.Add<OneToManyCascadeDeleteConvention>();
     modelBuilder.Conventions.Add<ManyToManyCascadeDeleteConvention>();
     base.OnModelCreating(modelBuilder);
 }

however I get the following error

"The DELETE statement conflicted with the REFERENCE constraint "FK_dbo.PLAYERS_M_dbo.COUNTRIES_PM_COUNTRY". The conflict occurred in database "MpContext", table "dbo.PLAYERS_M", column 'PM_COUNTRY'."

if you have observed the foreign key PM_COUNTRY is nullable int.

so I was expecting EF to delete the countries record and set PM_COUNTRY to null

am I doing something wrong?

I'm not sure why the convention isn't working, but you can configure it like this (after renaming the Entities):

modelBuilder.Entity<Player>()
    .HasOptional(c => c.Country)
    .WithMany()
    .HasForeignKey(p => p.CountryID)
    .WillCascadeOnDelete(true);

OP wants to DELETE a COUNTRIES record and expects that all PLAYERS_M that have the corresponding PM_COUNTRY value will be set to null.

To achieve this, PLAYERS_M.PM_COUNTRY is correctly defined as nullable field ( int? ) but you still need to declare the relationship as optional in the model to enforce this behaviour.

OneToManyCascadeDeleteConvention does not help here, according to the documentation: Convention to enable cascade delete for any required relationships.

To get around this you can add the following Fluent Notation to your OnModelCreating method:

modelBuilder.Entity<PLAYERS_M>()
            .HasOptional(p => p.COUNTRIES) 
            .WithMany() 
            .HasForeignKey(p => p.PM_COUNTRY)
            .WillCascadeOnDelete(true); // this is where the magic is!

This behaviour is most likely by design, using Cascade Delete like this to null out optional references can very quickly create orphaned records, by using fluent notation you are forced to make the business decision for each relationship individually. Use this feature with care.

I've solved my problem by adding the below property to the COUNTRIES class

[ForeignKey("PM_COUNTRY")]
public virtual List<PLAYERS_M> PLAYERS_M { get; set; } 

public class COUNTRIES
{
    [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int CO_ROWID { get; set; }
    public string CO_CODE { get; set; }
    public string CO_NAME { get; set; }

    [ForeignKey("PM_COUNTRY")]
    public virtual List<PLAYERS_M> PLAYERS_M { get; set; }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM