Entity Framework не удаляет строки из других таблиц - PullRequest
0 голосов
/ 13 января 2020

В настоящее время, когда я пытаюсь удалить 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 сопоставляется с сгенерированный магазином столбец. Колонка: 'SubjectId'

Я часами бился об этом, пробуя разные вещи. (

Ответы [ 3 ]

0 голосов
/ 13 января 2020

Глядя на ваш код, вам все еще нужно больше работать. Классы сущностей не завершены. Узнайте больше о кодах первых сущностей классов здесь. Начальное приложение Entity Framework

Когда вы ссылаетесь на сущность в классе 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; }
}
0 голосов
/ 13 января 2020

Существуют различные способы структурирования ваших сущностей, которые облегчают эту задачу, однако для начала давайте добавим метод к вашему классу 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);
}

Кажется, ваша модель имеет минимальные поля, необходимые для ее поддержки, однако вы не включили никаких внешних ключей в таблицы Зависимые , поэтому модель не знает о том, что записи ДОЛЖНЫ зависят от их связи с Subject.

Фактически, НЕ , определяющей отношение, модель предполагает , что связанный ключи, которые он генерирует от вашего имени, на самом деле являются необязательными , что означает, что записи 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);

(Или вы можете просто откомментировать строки, которые добавляют delete cascade условные обозначения. )

Это окончательный вывод, если вам нужен доступ к фактическим полям Внешний ключ , которые используются для принудительного применения навигационных ссылок, или если это 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; }
}
0 голосов
/ 13 января 2020

Я думаю, что стоит прочитать некоторые основы EntityFramework на https://www.entityframeworktutorial.net/code-first/cascade-delete-in-code-first.aspx.

Ваша модель нуждается в некоторых модификациях, так как для выполнения каскадного удаления вам потребуется перекрестная ссылка на одну модель в другой , Это отсутствует в таблице SubjectFaces.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...