簡體   English   中英

實體框架:如何在更新或刪除“通用”父對象時刪除相關實體

[英]Entity Framework: how to delete related entity upon update or delete of 'generic' parent

我有一個Product類,其中包含一個Picture屬性。 其他類也可能有圖片,例如Customer可以有Picture

Product.cs:

public class Product
{
    public Picture Picture { get; set; }
} 

Customer.cs:

public class Customer
{
    public Picture Picture { get; set; }
} 

Picture.cs:

public class Picture
{
    public string Type { get; set; }

    public byte[] Content { get; et; }
}

圖片始終是可選的 ,即產品和客戶可能有也可能沒有圖片。 但是,圖片唯一地鏈接到一個“父”實體(產品或客戶)。 沒有父母,圖片就沒有用。 請注意,從Picture到父類沒有鏈接,因為該父類可以是多種類型(產品或客戶)。

另一個要求是我想通過急切或延遲加載來完全控制是否加載圖片。 例如,當檢索產品列表時,我不希望獲取圖片,但是如果需要單個產品,則應包含圖片。

我的問題 :如何配置實體框架,以便:

  • 當刪除母公司(產品或客戶)記錄時,將刪除圖片記錄
  • 每當父記錄更新且新版本不包含圖片時,圖片記錄即被刪除。
  • 每當使用新圖片更新父級時,圖片記錄即被替換(刪除+創建記錄)
  • 圖片是可選的
  • 始終控制圖片是否已加載

我正在使用流暢的API來定義關系。 當前,沒有任何級聯刪除。

public class ProductMap : EntityTypeConfiguration<Product>
{
    public ProductMap()
    {
        ToTable("PRODUCTS");

        HasKey(x => x.Id);

        HasOptional(x => x.Picture).WithOptionalDependent().Map(m => m.MapKey("PICTUREID"));
    }
}

我嘗試使用WithRequired,但這會產生錯誤,因為從PictureProduct/Customer沒有鏈接或外鍵。

您可以執行以下操作:

public abstract class Picture
{
    public int Id {get;set;}
    public string Type { get; set; }
    public byte[] Content { get; set; }
}

public class ProductImage:Picture
{
    public int ProductId {get;set;}
    public virtual Product Product {get;set;}
}
public class CustomerImage:Picture
{
   public int CustomerId {get;set;}
   public virtual Customer Customer{get;set;}
}

那么您可以像這樣配置:ex。 產品:

HasOptional(x=>x.ProductImage)
 .withRequired(x=>x.Product)
 .HasForeignKey(x=>x.ProductId); //cascade on delete is default true

這樣,您可以在需要時加載圖片,並且如果刪除產品項目,圖像也將被刪除。 該圖像是可選的,並且可以替換。 更新時,您必須指定新圖像或刪除舊圖像。

希望這種替代方法將幫助您選擇所需的確切對象。

我認為您可以將Picture配置為ComplexType ,這將在父表中創建Picture類列的屬性。

這意味着:

  • 每當刪除父對象時,都會刪除相應的Picture
  • 每當使用新的Picture數據(更新的圖片數據或無數據)更新父對象時,父表中的相應列也會更新。

此處介紹了如何將Picture實體配置為ComplexTypehttp : ComplexType

至少這是您需要做的:

public class MyDbContext:DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.ComplexType<Picture>();
    }
}

如果運行migration則可能會生成類似於以下內容的遷移:

    public override void Up()
    {
        CreateTable(
            "dbo.Customers",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Picture_Type = c.String(),
                    Picture_Content = c.Binary(),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.Products",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    Picture_Type = c.String(),
                    Picture_Content = c.Binary(),
                })
            .PrimaryKey(t => t.Id);

    }

另外,您還可以為ComplexType編寫流暢的配置,如下所示:

public class PictureConfig : ComplexTypeConfiguration<Picture>
{
    public PictureConfig()
    {
        Property(t => t.Type).HasColumnName("PictureType");
        Property(t => t.Content).HasColumnName("PictureContent");
    }
}

並在DbContext添加此配置:

public class MyDbContext:DbContext
{
    public DbSet<Customer> Customers { get; set; }
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //modelBuilder.ComplexType<Picture>();
        modelBuilder.Configurations.Add(new PictureConfig());
    }
}

如果現在使用add-migration ,它可能如下所示:

    public override void Up()
    {
        CreateTable(
            "dbo.Customers",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    PictureType = c.String(),
                    PictureContent = c.Binary(),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.Products",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    PictureType = c.String(),
                    PictureContent = c.Binary(),
                })
            .PrimaryKey(t => t.Id);

    }

希望這可以幫助。

根據評論進行更新:更新的這一部分並沒有真正提供您想要的內容,而只是提出了建議。

我認為您正在尋找的關系如下:

Product---1-----1---Picture ---1------1---Customer
|- Id               |- Id                 |- Id
|- PictureId?                             |- PictureId?

也就是說,您可以在父類上保留nullable PictureId ,並在更改圖片時更改此PictureId

缺點:您需要自己管理數據操作活動(CRUD)。

優點:這樣,您可以完全控制何時加載圖像,因為加載父級不會自動加載Picture 此外,這還使您能夠將Picture與數據庫解耦,並使用某種形式的Blob存儲(可能在雲中)。

我也在StackOverflow上找到了這個,也許對您有幫助:

modelBuilder.Entity<Product>()
    .HasKey(c => c.Id)
    .HasRequired(c => c.User)
    .WithRequiredDependent(c => c.UserProfile)
    .WillCascadeOnDelete(true);

我認為您需要稍微更改代碼,但它應該可以工作...

原始帖子: EF代碼第一個Fluent API-級聯刪除

也許這也可以為您提供幫助: 使用Fluent API進行級聯刪除

添加呼叫以刪除要刪除產品的圖片。 如果要在許多地方執行此操作,請重新分解以封裝此操作。 我發現EF配置不透明,但是在DeleteProduct方法或DeleteCustomer方法中對delete的簡單調用很容易閱讀和理解。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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