我尝试使用Entity Framework Code First进行多对多关系。
对象为CARD
和USER_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<USER_LIST>
并将其设置为针对USER_LIST
对象的CARD
属性。致电SaveChanges()
时,会产生以下结果(如预期的那样):
MyCardObject.USER_LIST = MyListOfUsers;
MyDBContext.SaveChanges();
可以看出,正确的条目已根据需要插入到CARDUSER表中。
当我尝试删除CARD时出现的问题:
MyDBContext.CARD.Remove(MyCardObject);
MyDBContext.SaveChanges();
以上将从CARD表中删除CARD记录;但是,CARDUSER中与此CARD相关的所有记录仍然存在:
我遇到了以下问题,希望这会回答我的问题:
How delete many-to-many relation in Entity Framework 6
但是,我已经在DBContext中定义了“多对多”映射,而无需显式定义CARDUSER
对象,因此我无法针对每个State
对象设置CARDUSER
到Deleted
。
为什么这些数据在CARDUSER表中存在,以及如何设置它以便CARDUSER中的CARD_ID和USER_ID字段都是正确的,强制的外键值?我已经尝试在数据库本身的CARDUSER表上设置外键约束;但是,如果我这样做,那么当我针对USER_LIST
对象设置CARD
属性然后尝试保存更改时,会导致CARDUSER
内的外键违规,系统尝试重新插入已针对CARD
设置的所有条目。
答案 0 :(得分:0)
在多对多关系中,您必须有一个交叉/桥牌表 你可以在你发布的链接中看到他有一个联结表。
答案 1 :(得分:0)
当您向连接表添加外键约束时,您处于正确的轨道上。 SQL Server(默认情况下)不会cascade
通过外键关系删除,这就是您(正确地)收到错误的原因。如果将外键定义为on delete cascade
,您将获得所需的行为。
或者,您可以在没有级联行为的情况下定义外键。如果这样做,您必须确保手动删除连接表中的条目。