简体   繁体   中英

Entity Framework Many to Many relationship leaves data in joining table

I have attempted a Many-to-Many relationship using Entity Framework Code First.

The objects are CARD and USER_LIST ; a CARD can have many USER_LIST assigned to it and a single USER_LIST can be assigned to many CARD .

The classes are defined as follows:

public partial class CARD : DBEntityItem {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]

        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int CARD_ID { get; set; }

        [StringLength(500)]
        public string SHORT_DESC { get; set; }

        public int STAGE_ID { get; set; }

        public int GROUP_ID { get; set; }

        public int FLAGS { get; set; }

        [StringLength(30)]
        public string OFFICE_APP_REF { get; set; }

        [StringLength(7)]
        public string CARD_COLOUR { get; set; }

        public int CTYPE_ID { get; set; }

        public virtual GROUP GROUP { get; set; }

        public virtual CARD_TYPE CARD_TYPE { get; set; }

        public virtual STAGE STAGE { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<USER_LIST> USER_LIST { get; set; }

        [NotMapped]
        public CardFlags FlagOptions { get; set; }

        public enum CardFlags {
            None = 0,
            Blocked = 1,
            Unexpected = 2,
            Emergency = 4,
            Failed = 8
        }

        public CARD()
            : base("CARD", "CARD_ID") {
            USER_LIST = new HashSet<USER_LIST>();
        }
    }

public partial class USER_LIST : DBEntityItem {
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int USER_ID { get; set; }

    [Required]
    [StringLength(100)]
    public string USER_NAME { get; set; }

    [Required]
    [StringLength(250)]
    public string PASSWORD { get; set; }

    [StringLength(250)]
    public string EMAIL { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PREFERENCE_VALUE> PREFERENCE_VALUE { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<USER_PERMISSIONS> USER_PERMISSIONS { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<USER_TASK> USER_TASK { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<CARD> CARD { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<CHANGE_NOTE> CHANGE_NOTE { get; set; }

    public USER_LIST()
        : base("USER_LIST", "USER_ID") {
        PREFERENCE_VALUE = new HashSet<PREFERENCE_VALUE>();
        USER_PERMISSIONS = new HashSet<USER_PERMISSIONS>();
        USER_TASK = new HashSet<USER_TASK>();
        CARD = new HashSet<CARD>();
    }
}

Ignore the inheritance from DBEntityItem and the resulting constructor chain as that is simply a class that is used to give the Entities some additional functionality.

The Many-to-Many mapping is defined within OnModelCreating as follows:

modelBuilder.Entity<CARD>()
    .HasMany(e => e.USER_LIST)
    .WithMany(e => e.CARD)
    .Map(m => {
        m.MapLeftKey("CARD_ID");
        m.MapRightKey("USER_ID");
        m.ToTable("CARDUSER");
        });

This is due to 'CARDUSER' being an existing table in the database.

A List<USER_LIST> is built up and is set as the USER_LIST property against a CARD object. When calling SaveChanges() , this results in the following (as expected):

MyCardObject.USER_LIST = MyListOfUsers;
MyDBContext.SaveChanges();

CARDUSER表数据

As can be seen, the correct entries have been inserted into the CARDUSER table as required.

The issue I have arises when I try to delete the CARD:

MyDBContext.CARD.Remove(MyCardObject);
MyDBContext.SaveChanges();

The above will remove the CARD record from the CARD table; however, all of the records pertaining to this CARD within CARDUSER are still there:

CARD表中没有任何内容,但CARDUSER仍然包含数据

I came across the following question and had hoped that this would answer my question:

How delete many-to-many relation in Entity Framework 6

However, I have defined the Many-to-Many mapping within the DBContext without the need to explicitly define a CARDUSER object and I therefore cannot set the State against each CARDUSER object to Deleted .

Why is it that this data is hanging around in the CARDUSER table and how can this be set up so that both the CARD_ID and USER_ID fields within CARDUSER are proper, enforced Foreign Key values? I have tried setting Foreign Key constraints on the CARDUSER table within the database itself; however, if I do that, then when I set the USER_LIST property against the CARD object and then try to save the changes, it results in a Foreign Key Violation within CARDUSER , with the system attempting to re-insert all of the entries that were already set against the CARD .

In a Many-to-Many Relationship you must have a junction/bridge table.
You can see in the link that you posted, he has a junction table.

You were on the right track when you added a foreign key constraint to the join table. SQL Server (by default) will not cascade a deletion through foreign key relationships, which is why you (rightfully) receive an error. If you define the foreign keys as on delete cascade you will get the behavior you want.

Alternatively, you can define the foreign key without the cascade behavior. If you do that, you've got to make sure you delete the entries in the join table manually.

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