【问题标题】:Entity Framework Many to Many relationship leaves data in joining table实体框架多对多关系将数据留在连接表中
【发布时间】:2017-04-27 18:23:16
【问题描述】:

我尝试了使用实体框架代码优先的多对多关系。

对象是CARDUSER_LIST;一个CARD 可以分配多个USER_LIST,一个USER_LIST 可以分配给多个CARD

类定义如下:

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>();
    }
}

忽略来自DBEntityItem 的继承和生成的构造函数链,因为它只是一个用于为实体提供一些附加功能的类。

多对多映射在OnModelCreating 中定义如下:

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");
        });

这是因为“CARDUSER”是数据库中的现有表。

List&lt;USER_LIST&gt; 已构建并设置为针对 CARD 对象的 USER_LIST 属性。调用SaveChanges() 时,结果如下(如预期):

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

可以看出,正确的条目已按要求插入到 CARDUSER 表中。

我尝试删除卡时出现的问题:

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

以上将从 CARD 表中删除 CARD 记录;但是,CARDUSER 中与此 CARD 相关的所有记录仍然存在:

我遇到了以下问题,并希望这能回答我的问题:

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

但是,我已经在 DBContext 中定义了多对多映射,而无需显式定义 CARDUSER 对象,因此我无法将每个 CARDUSER 对象的 State 设置为 Deleted

为什么这些数据在 CARDUSER 表中徘徊,如何设置它以使 CARDUSER 中的 CARD_ID 和 USER_ID 字段都是正确的强制外键值?我尝试在数据库本身的 CARDUSER 表上设置外键约束;但是,如果我这样做,那么当我针对CARD 对象设置USER_LIST 属性然后尝试保存更改时,它会导致CARDUSER 中的外键冲突,系统会尝试重新插入已针对 CARD 设置的所有条目。

【问题讨论】:

  • 看起来你已经删除了ManyToManyCascadeDeleteConvention

标签: c# database entity-framework many-to-many


【解决方案1】:

在多对多关系中,您必须有一个联结/桥接表。
您可以在您发布的链接中看到,他有一个联结表。

【讨论】:

    【解决方案2】:

    当您向连接表添加外键约束时,您走在了正确的轨道上。 SQL Server(默认情况下)不会通过外键关系cascade 删除,这就是您(理所当然地)收到错误的原因。如果您将外键定义为on delete cascade,您将获得您想要的行为。

    或者,您可以定义没有级联行为的外键。如果这样做,则必须确保手动删除连接表中的条目。

    【讨论】:

    • 感谢您的回复;我可以看到你来自哪里;但是,从我的角度来看,我没有必要在数据库中定义级联删除;您应该能够将其定义为代码中模型的一部分。但是,当我定义 onModelCreating 中的多对多映射时,我没有“WillCascaseOnDelete”选项。现在,我正在手动删除联接表中的条目;但是,我仍然不明白为什么我不能在代码中构造它,以便当我删除 CARD 对象时,它知道它也需要删除 CARDUSER 记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-28
    • 2011-12-17
    • 1970-01-01
    相关资源
    最近更新 更多