簡體   English   中英

實體框架不從其他表中刪除行

[英]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 ,表SubjectFacesSubjectData中的行不會被刪除。

 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 ,這意味着FaceImageKVPair記錄應該單獨存在,而不是鏈接到Subject

FaceImageKVPair添加外鍵鏈接可以減少歧義:
注意:這里只添加了導航屬性

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM