删除自引用类的对象时出现DbUpdateException

时间:2019-05-24 16:21:36

标签: c# asp.net entity-framework

我目前正在开发一个系统,该系统可以生成和管理站点中图像的缩略图。基本上是为了缩短加载时间,在此之前创建较小的图像,这样就无需为每个请求进行任何预处理或加载原始的大图像。

目前创作工作正常,但是我无法删除图像(原始图像和生成图像)。当我直接从数据库中删除时,通过简单的删除就可以正常工作,但是当我通过代码进行删除时,它是行不通的。

“我的图像”表分为两个类


public class Image(){
  public int Id{ get; set;}
  public int? MainImageId{ get; set;}; 
  public string Description{ get; set;}
  public virtual Image MainImage{ get; set;}
  public virtual ImageContent Content{ get; set;}
  public virtual ICollection<Image> Variations{ get; set;}
}
public class ImageContent(){
  public int ImageId { get; set; }
  public byte[] Raw { get; set; }
  public virtual Image Image { get; set; }
}

它们的构建方式为

 modelBuilder.Entity<Image>()
  .HasRequired(x => x.Content)
  .WithRequiredDependent(x => x.Image);

modelBuilder.Entity<Image>()
  .ToTable("Images");            

modelBuilder.Entity<ImageContent>()
  .HasKey(x => x.ImageId)
  .ToTable("Images");

modelBuilder.Entity<Image>()
  .HasMany(i => i.Variations)
  .WithOptional(i => i.MainImage)
  .HasForeignKey(v => v.MainImageId);

我的删除功能是

public void Delete(int id){
  var image = context.Set<Image>().Include("Variations").FirstOrDefault(i => i.Id == id);

  if (image != null) {

    foreach(Image variation in image.Variations) {
      context.Set<Image>().Remove(variation);
    }

    context.Set<Image>().Remove(image);

    context.SaveChanges();
  }

}

但是当我运行Delete函数时,我收到一条DbUpdateException并显示消息Invalid data encountered. A required relationship is missing. Examine StateEntries to determine the source of the constraint violation.

运行context.SaveChanges()时引发错误。

我已经尝试包含所有依赖项,例如Content和Variations,并且找不到引发此错误的任何其他原因。

以前,该课程没有自我参考,一切正常。有人知道我能做些什么来解决这个问题吗?

1 个答案:

答案 0 :(得分:1)

 modelBuilder.Entity<Image>()
  .ToTable("Images");            

 modelBuilder.Entity<ImageContent>()
  .HasKey(x => x.ImageId)
  .ToTable("Images");

此处执行的操作称为表拆分,也就是说,数据库中有一个表Images,它被“拆分”为两个实体,ImageImageContent。删除包含拆分表的实体对时,一种实现方法是在包含从属实体的情况下删除 principal 实体。主要实体在映射中定义...

 modelBuilder.Entity<Image>()
  .HasRequired(x => x.Content)
  .WithRequiredDependent(x => x.Image);

哪个说:Image是依赖的,所以ImageContent是委托人。

有问题。

线路...

 context.Set<Image>().Remove(image);

...删除从属实体。

现在,您可以通过包含Content并将其标记为删除(现在忽略Variations)来轻松解决此问题:

using System.Data.Entity;
...

var image = context.Set<Image>().Include(i => i.Content)
                   .Single(i => i.Id == id);
context.Entry(image).State = EntityState.Deleted;
context.Entry(image.Content).State = EntityState.Deleted;

但是我认为当Image是主要实体时,该模型更有意义:

modelBuilder.Entity<Image>()
  .HasRequired(x => x.Content)
  .WithRequiredPrincipal(x => x.Image);

现在可以删除图像而无需显式删除Content

var image = context.Set<Image>().Include(i => i.Content)
                   .Single(i => i.Id == id);
context.Entry(image).State = EntityState.Deleted;
// or context.Set<Image>().Remove(image);

这也使删除变体更加容易:

var image = context.Set<Image>()
                   .Include(i => i.Content)
                   .Include(i => i.Variations.Select(v => v.Content))
                   .Single(i => i.Id == id);

foreach (var variation in image.Variations)
{
    context.Set<Image>().Remove(variation);
}
context.Set<Image>().Remove(image);

此外,这还使您能够通过仅从数据库中获取Image而没有(大)内容并通过 stub实体删除内容来使删除操作的成本降低。我将向您展示如何仅对一张图像进行操作:

var img1 = context.Set<Image>(). Single(i => i.Id == 1);
img1.Content = new ImageContent { ImageId = img1.Id }; // Stub entity
context.Entry(img1.Content).State = Entity.EntityState.Unchanged; // Attach to context
context.Set<Image>().Remove(img1);
context.SaveChanges();