C# 实体框架:更新或删除'时如何删除相关实体;通用';父母亲
我有一个C# 实体框架:更新或删除'时如何删除相关实体;通用';父母亲,c#,entity-framework,entity-framework-6,cascading-deletes,C#,Entity Framework,Entity Framework 6,Cascading Deletes,我有一个产品类,它包含一个图片属性。其他类也可能有图片,例如客户可以有图片 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 stri
产品
类,它包含一个图片
属性。其他类也可能有图片,例如客户
可以有图片
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与父类之间没有链接,因为父类可以是多种类型(产品或客户)
另一个要求是,我希望通过快速加载或延迟加载完全控制图片是否加载。例如,在检索产品列表时,我不希望获取图片,但如果请求单个产品,则应包括图片
我的问题:如何配置实体框架以便:
- 当父记录(产品或客户)被删除时,图片记录被删除
- 每当父记录更新且新版本不包含图片时,图片记录将被删除
- 每当父级更新为新图片时,图片记录将被替换(删除+创建记录)
- 图片是可选的
- 始终控制图片是否加载
public class ProductMap : EntityTypeConfiguration<Product>
{
public ProductMap()
{
ToTable("PRODUCTS");
HasKey(x => x.Id);
HasOptional(x => x.Picture).WithOptionalDependent().Map(m => m.MapKey("PICTUREID"));
}
}
公共类ProductMap:EntityTypeConfiguration
{
公共产品地图()
{
ToTable(“产品”);
HasKey(x=>x.Id);
has可选(x=>x.Picture).WithOptionalDependent().Map(m=>m.MapKey(“PICTUREID”);
}
}
我尝试使用WithRequired,但这会产生错误,因为从
图片
到产品/客户
没有链接或外键,我在StackOverflow上也发现了这一点,也许它会帮助您:
modelBuilder.Entity<Product>()
.HasKey(c => c.Id)
.HasRequired(c => c.User)
.WithRequiredDependent(c => c.UserProfile)
.WillCascadeOnDelete(true);
modelBuilder.Entity()
.HasKey(c=>c.Id)
.HasRequired(c=>c.User)
.WithRequiredDependent(c=>c.UserProfile)
.WillCascadeOnDelete(真);
我认为你需要改变你的代码一点,但它应该工作
原职:
也许这对您也有帮助:我认为您可以将
图片
配置为ComplexType
,从而在父表中创建图片
类列的属性
这意味着:
- 无论何时删除父对象,都会删除相应的
图片
- 每当使用新的
数据(更新的图片数据或无数据)更新父表时,父表中的相应列也会更新图片
图片
实体配置为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>();
}
}
此外,您还可以为ComplexType
编写流畅的配置,如下所示:
public class PictureConfig : ComplexTypeConfiguration<Picture>
{
public PictureConfig()
{
Property(t => t.Type).HasColumnName("PictureType");
Property(t => t.Content).HasColumnName("PictureContent");
}
}
如果现在添加迁移,它可能如下所示:
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);
}
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?
希望这有帮助
根据评论更新:
更新的这一部分并没有给你真正想要的东西,只是提供了一个简单的建议
我认为你正在寻找一种如下的关系:
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);
}
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)
优点:这样您可以完全控制何时加载图像,因为加载父对象不会自动加载
图片。此外,这还使您能够将图片与数据库解耦,并使用某种blob存储(可能在云端或其他位置)。添加调用以删除要删除产品的图片。如果您在许多地方这样做,请重新考虑封装此操作。我发现EF配置不够透明,但是在DeleteProduct方法或DeleteCustomer方法中简单地调用delete很容易阅读和理解 您可以执行以下操作:
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;}
}
然后您可以这样配置:
例如,对于产品:
HasOptional(x=>x.ProductImage)
.withRequired(x=>x.Product)
.HasForeignKey(x=>x.ProductId); //cascade on delete is default true
通过这种方式,您可以在需要时加载图片,如果删除产品项,图像也将被删除。
图像是可选的,可以替换。
更新时,必须指定新图像或删除旧图像
希望这个选择能帮助你准确地选择你想要的 这要求依赖类有一个引用父类的属性(UserProfile有一个名为User的属性),在我的情况下不是这样。这种关系需要是单向的。为什么还要创建一个单独的表,里面有图片,而产品/用户表本身没有图片信息?你从中受益了吗?或者你在任何地方都需要它吗?因为图片是一个很大的数据块,我想控制何时获取它,何时不获取它。因为我不能告诉实体框架忽略一列,但我可以告诉实体框架忽略一个关系,这就是我设计它的方式。嗯,但你可以告诉EF忽略一列,只要不选择它。你可以通过将LazyLoading
设置为false,告诉EF不加载关系!谢谢你的回答,我觉得很有趣。然而,我遇到了两个问题。一是复杂类型不能为null。由于图片始终是可选的,这是一个问题。第二,我想完全控制何时加载图片,何时不加载,因为它是一个大文件。这个级别