[英]Entity Framework not deleting rows from other tables
目前,當我嘗試刪除一個Subject
,它會被刪除,但其他表中與該主題相對應的行被遺棄了。
這是我的模型
public class SubjectsDbContext : DbContext
{
public virtual DbSet<Subject> Subjects { get; set; }
public virtual DbSet<FaceImage> EnrolledFaces { get; set; }
public virtual DbSet<KVPair> KeyValuePairs { get; set; }
public SubjectsDbContext(string connectionString) : base(connectionString)
{
}
public SubjectsDbContext()
{
}
}
public class Subject
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid SubjectId { get; set; }
[Required]
public virtual FaceImage EnrolledFace {get;set;}
[Required]
public DateTimeOffset EnrolledTime { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(64)]
public string BiometricId { get; set; }
public virtual ICollection<KVPair> KeyValues { get; set; }
public Subject()
{
KeyValues = new List<KVPair>();
}
}
[Table("SubjectFaces")]
public class FaceImage
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid FaceId { get; set; }
[Required]
public byte[] Image { get; set; }
}
[Table("SubjectData")]
public class KVPair
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid KvPairId { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Key { get; set; }
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Value { get; set; }
}
現在,當我嘗試刪除Subject
,表SubjectFaces
和SubjectData
中的行不會被刪除。
var subject = dbContext.Subjects.Where(a => a.SubjectId == subjectId).FirstOrDefault();
if(subject != null)
{
dbContext.Subjects.Remove(subject);
}
else
{
throw new Exception($"Subject not found");
}
dbContext.SaveChanges();
我認為我的模型不正確,我該如何正確注釋它?
更新:
克里斯的回應后,我已將模型更改為此
public class Subject
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid SubjectId { get; set; }
[Required]
public virtual FaceImage EnrolledFace {get;set;}
[Required]
public DateTimeOffset EnrolledTime { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(64)]
public string BiometricId { get; set; }
public virtual ICollection<KVPair> KeyValues { get; set; }
public Subject()
{
KeyValues = new List<KVPair>();
}
}
[Table("SubjectFaces")]
public class FaceImage
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid FaceId { get; set; }
[Required]
public byte[] Image { get; set; }
[ForeignKey(nameof(SubjectId))]
public virtual Subject Subject { get; set; }
[Required]
public Guid SubjectId { get; set; }
}
[Table("SubjectData")]
public class KVPair
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid KVPairId { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Key { get; set; }
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Value { get; set; }
[ForeignKey(nameof(SubjectId))]
public virtual Subject Subject { get; set; }
[Required]
public Guid SubjectId { get; set; }
}
但是,當我嘗試創建一個新的Subject
,我現在遇到了這個異常。
ReferentialConstraint 中的依賴屬性映射到存儲生成的列。 列:“主題 ID”
幾個小時以來,我一直在努力嘗試不同的事情。 :(
我認為值得在https://www.entityframeworktutorial.net/code-first/cascade-delete-in-code-first.aspx閱讀 EntityFramework 的一些基礎知識。
您的模型需要一些修改才能執行級聯刪除,您需要在另一個模型中交叉引用一個模型。 這在 SubjectFaces 表中是缺失的。
看看你的代碼,你還需要做更多的工作。 實體類不完整。 在此處閱讀有關代碼優先實體類的更多信息。 實體框架初始應用
當您在 Subject 類中引用一個實體時,您還需要在子實體中引用這個 Subject。
public class Subject
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid SubjectId { get; set; }
[Required]
public virtual long EnrolledFaceId {get;set;} //
[ForeignKey("EnrolledFaceId")]
public virtual FaceImage EnrolledFace {get;set;}
[Required]
public DateTimeOffset EnrolledTime { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(64)]
public string BiometricId { get; set; }
public virtual ICollection<KVPair> KeyValues { get; set; }
public Subject()
{
KeyValues = new List<KVPair>();
}
}
[Table("SubjectFaces")]
public class FaceImage
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid FaceId { get; set; }
//Add a reference to the Subject
[Required]
public Subject Subject { get; set; }
public long SubjectId { get; set; }
[Required]
public byte[] Image { get; set; }
}
[Table("SubjectData")]
public class KVPair
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid KvPairId { get; set; }
//Add a reference to the Subject
[Required]
public long SubjectId { get; set; }
[ForeignKey("SubjectId")]
public Subject Subject { get; set; }
[Required]
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Key { get; set; }
[Column(TypeName = "varchar")]
[StringLength(128)]
public string Value { get; set; }
}
有多種不同的方法可以讓您更輕松地構建實體,但首先讓我們向您的SubjectsDbContext
類添加一個方法,以使用流暢的表示法來強制執行級聯刪除行為:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Normally these conventions should easily target your entire model to support cascade delete
//modelBuilder.Conventions.Add(new OneToManyCascadeDeleteConvention());
//modelBuilder.Conventions.Add(new ManyToManyCascadeDeleteConvention());
// However you many not want the entire model to cascade,
// or due to the relationshipships not being explicitly defined so the above conventions
// may not resolve correctly.
// These statements explicitly define the relationships and the cascade operation
modelBuilder.Entity<Subject>().HasMany(x => x.KeyValues).WithRequired().WillCascadeOnDelete(true);
modelBuilder.Entity<Subject>().HasRequired(x => x.EnrolledFace).WithRequiredPrincipal().WillCascadeOnDelete(true);
}
您的模型似乎具有支持它所需的最少字段,但是您沒有在Dependent表中包含任何外鍵,因此模型不知道相關記錄必須依賴於它們與Subject
的鏈接。
事實上,通過不指定關系,模型假設它代表您生成的相關鍵實際上是optional ,這意味着FaceImage
和KVPair
記錄應該單獨存在,而不是鏈接到Subject
。
在FaceImage
和KVPair
添加外鍵鏈接可以減少歧義:
注意:這里只添加了導航屬性
public class FaceImage
{
...
[Required]
public virtual Subject Subject { get; set; }
}
public class KVPair
{
...
[Required]
public virtual Subject Subject { get; set; }
}
有了這個改變,為了在OnModelCreating
方法中定位這些關系,我們需要稍微改變流暢的表示法:
modelBuilder.Entity<Subject>().HasMany(x => x.KeyValues).WithRequired(x => x.Subject).WillCascadeOnDelete(true);
modelBuilder.Entity<Subject>().HasRequired(x => x.EnrolledFace).WithRequiredPrincipal(x => x.Subject).WillCascadeOnDelete(true);
(或者您可以取消注釋添加刪除級聯約定的行。)
這是最后的推導,如果您需要訪問用於強制執行導航鏈接的實際外鍵字段,或者如果這是Code First實現並且您想影響這些字段的名稱,那么您只需添加這些字段也包含在類中:
public class FaceImage
{
...
[Required]
public Guid SubjectId { get; set; }
[ForeignKey(nameof(SubjectId))]
public virtual Subject Subject { get; set; }
}
public class KVPair
{
...
[Required]
public Guid SubjectId { get; set; }
[ForeignKey(nameof(SubjectId))]
public virtual Subject Subject { get; set; }
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.