简体   繁体   English

实体框架:如何在更新或删除“通用”父对象时删除相关实体

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

I have a Product class, which contains a Picture property. 我有一个Product类,其中包含一个Picture属性。 Other classes may also have a picture, eg a Customer can have a Picture . 其他类也可能有图片,例如Customer可以有Picture

Product.cs: Product.cs:

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

Customer.cs: Customer.cs:

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

Picture.cs: Picture.cs:

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

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

The picture is always optional , ie Products and Customers may or may not have a picture. 图片始终是可选的 ,即产品和客户可能有也可能没有图片。 However, a picture is uniquely linked to exactly one 'parent' entity (either a Product or a Customer). 但是,图片唯一地链接到一个“父”实体(产品或客户)。 Without the parent, there's no use for the Picture to exist. 没有父母,图片就没有用。 Note that there's no link from Picture to the parent class, because this parent can be of multiple types (Product or Customer). 请注意,从Picture到父类没有链接,因为该父类可以是多种类型(产品或客户)。

Another requirement is that I want to have full control over whether the picture is loaded or not, through eager or lazy loading . 另一个要求是我想通过急切或延迟加载来完全控制是否加载图片。 Eg when retrieving a list of products, I don't want the picture to be fetched, but if a single product is requested, the picture should be included. 例如,当检索产品列表时,我不希望获取图片,但是如果需要单个产品,则应包含图片。

My question : how can I configure Entity Framework so that: 我的问题 :如何配置实体框架,以便:

  • The Picture record is deleted when the parent (product or customer) record is deleted 当删除母公司(产品或客户)记录时,将删除图片记录
  • The Picture record is deleted whenever the parent record is updated and the new version does not contain a picture 每当父记录更新且新版本不包含图片时,图片记录即被删除。
  • The Picture record is replaced (delete + create of a record) whenever the parent is updated with a new picture 每当使用新图片更新父级时,图片记录即被替换(删除+创建记录)
  • The picture is optional 图片是可选的
  • Always keep control over whether the picture is loaded or not 始终控制图片是否已加载

I'm using fluent API to define the relationship. 我正在使用流畅的API来定义关系。 Currently, there's no cascading delete whatsoever. 当前,没有任何级联删除。

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

        HasKey(x => x.Id);

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

I tried using WithRequired but this generates errors because there's no link or foreign key from Picture to Product/Customer . 我尝试使用WithRequired,但这会产生错误,因为从PictureProduct/Customer没有链接或外键。

you can do as follow: 您可以执行以下操作:

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;}
}

then you can configuer like this: ex. 那么您可以像这样配置:ex。 for product: 产品:

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

In this way you can load picture when you need it, and if you delete product item, the image will be deleted as well. 这样,您可以在需要时加载图片,并且如果删除产品项目,图像也将被删除。 The image is optional, and can be replaced. 该图像是可选的,并且可以替换。 On update you must specified a new image or delete the old image. 更新时,您必须指定新图像或删除旧图像。

Hope this alternative will help you chose exact what you want. 希望这种替代方法将帮助您选择所需的确切对象。

I think you can configure the Picture as ComplexType that will make the properties of Picture class columns in the parent table. 我认为您可以将Picture配置为ComplexType ,这将在父表中创建Picture类列的属性。

This means: 这意味着:

  • Whenever the parent is deleted, the corresponding Picture is deleted. 每当删除父对象时,都会删除相应的Picture
  • Whenever the parent is updated with new Picture data (updated picture data or no data), corresponding columns in the parent table are also updated. 每当使用新的Picture数据(更新的图片数据或无数据)更新父对象时,父表中的相应列也会更新。

How you can configure the Picture entity as ComplexType is described here: http://weblogs.asp.net/manavi/entity-association-mapping-with-code-first-part-1-one-to-one-associations . 此处介绍了如何将Picture实体配置为ComplexTypehttp : ComplexType

Minimally this is what you need to do: 至少这是您需要做的:

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>();
    }
}

If you run migration then possibly it will generate the migrations similar to following: 如果运行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);

    }

Additionally you can also write fluent configuration for ComplexType as follows: 另外,您还可以为ComplexType编写流畅的配置,如下所示:

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

and add this configuration in DbContext : 并在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());
    }
}

If you now add-migration , it might look like the following: 如果现在使用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);

    }

Hope this helps. 希望这可以帮助。

Update based on comment: This part of the update does not really give you exactly what you want, but rather makes a mere suggestion. 根据评论进行更新:更新的这一部分并没有真正提供您想要的内容,而只是提出了建议。

I think you are looking for a relation like the following: 我认为您正在寻找的关系如下:

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

That is, you may keep nullable PictureId on the parent classes, and change this PictureId , whenever, the picture is changed. 也就是说,您可以在父类上保留nullable PictureId ,并在更改图片时更改此PictureId

Disadvantage:You need to manage the data manipulation activity (CRUD) on your own. 缺点:您需要自己管理数据操作活动(CRUD)。

Advantage:This way you have full control over when to load the image, as loading the parent does not load the Picture automatically. 优点:这样,您可以完全控制何时加载图像,因为加载父级不会自动加载Picture Also this enables you to decouple the Picture from your database and use some sort of blob storage (may be on cloud or so). 此外,这还使您能够将Picture与数据库解耦,并使用某种形式的Blob存储(可能在云中)。

I found this here on StackOverflow as well and maybe it will help you: 我也在StackOverflow上找到了这个,也许对您有帮助:

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

I think you need to change your code a little bit but it should work... 我认为您需要稍微更改代码,但它应该可以工作...

Original Post: EF Code First Fluent API - Cascade Delete 原始帖子: EF代码第一个Fluent API-级联删除

Maybe this can help you as well: Cascade delete using Fluent API 也许这也可以为您提供帮助: 使用Fluent API进行级联删除

Add the call to delete the Picture where you are deleting the the product. 添加呼叫以删除要删除产品的图片。 If you are doing this in a number of places re-factor to encapsulate this operation. 如果要在许多地方执行此操作,请重新分解以封装此操作。 I find the EF configurations to be less than transparent but a simple call to delete in a DeleteProduct method or DeleteCustomer method are easy to read and understand. 我发现EF配置不透明,但是在DeleteProduct方法或DeleteCustomer方法中对delete的简单调用很容易阅读和理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM