entity-framework - EF Core 5 - 如何向多对多关系添加自定义字段以指示乘数?
问题描述
我正在使用 .NetCore Razor Pages 构建一个网站,就像一个作品集,用户可以在其中上传一些照片,然后将它们显示在不同的页面上。每个页面都可以通过一些属性来定制,这些属性存储在数据库中图像的路径旁边。为了加快每个页面的构建阶段,我想实现行模板。
我有两个类:一个代表模板,另一个代表模板的组件。我的目标是使用先前创建的组件构建不同的模板,然后使用它们创建已经拆分为 TemplateComponent 空间属性长度的(引导)列的行。
到目前为止,EFCore 创建了实体来创建模板和组件之间的关系,但是这样每个组件只能与每个模板建立一次关系,从而拒绝使用 2 倍长度的组件构建模板的能力6.
如何编辑关系,以添加在同一组件上多次构建模板的机会?
到目前为止,我有这两个模型(以及它们各自在 DB 中的实体,由 EF Core 创建)和 DbContext 类:
public class Template
{
[Key]
public int Id { get; set; }
[Required]
public string ImagePath{ get; set; }
public List<TemplateComponent> Components { get; set; }
}
public class TemplateComponent
{
[Key]
public int Id { get; set; }
[Range(0,12)]
public int Space{ get; set; }
public List<Template> Rows{ get; set; }
}
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<TemplateComponent> TemplateComponents{ get; set; }
public DbSet<Template> Templates{ get; set; }
}
}
解决方案
在幕后 EFCore 5 将创建一个链接表,可能称为 TemplateComponentTemplates 或 TemplateTemplateComponents。该表将仅包含一个 TemplateId 和一个 TemplateComponentId。要将任何其他列附加到此表中,例如数量或支持同一模板上的多个组件,您将需要显式声明此连接实体。
为了简化命名约定,我将您所称的 TemplateComponent 重命名为 Component,这样 TemplateComponent 将反映连接实体。
第一步是更新我们的“多”引用类型以使用连接实体:
public class Template
{
[Key]
public int Id { get; set; }
[Required]
public string ImagePath{ get; set; }
public virtual ICollection<TemplateComponent> TemplateComponents { get; set; } = new List<TemplateComponent>();
}
public class Component
{
[Key]
public int Id { get; set; }
[Range(0,12)]
public int Space{ get; set; }
public virtual ICollection<TemplateComponent> TemplateComponents { get; set; } = new List<TemplateComponent>();
}
应声明“多”侧导航属性,virtual ICollection<TEntity>
以便 EF 可以正确连接代理以进行更改跟踪。
现在,根据您希望如何表达模板和组件之间的多重性,TemplateComponent 实体可能类似于:
public class TemplateComponent
{
[Key, Column(Order-0), ForeignKey(Template)]
public int TemplateId { get; set; }
[Key, Column(Order-1), ForeignKey(Component)]
public int Component { get; set; }
public int Quantity { get; set; } = 1;
public virtual Template Template { get; set; }
public virtual Component Component { get; set; }
}
在组件和特定模板之间会有一个链接记录,但有一个附加字段来表示该模板和组件关联的乘数或数量。
或者,如果您想支持可以为每个组合设置此连接记录的多个实例的连接(可能为每个组合提供附加信息列):
public class TemplateComponent
{
[Key]
public int Id { get; set; }
[ForeignKey(Template)]
public int TemplateId { get; set; }
[ForeignKey(Component)]
public int Component { get; set; }
public virtual Template Template { get; set; }
public virtual Component Component { get; set; }
}
这里的区别在于 TemplateComponent 获得了自己唯一的 PK 而不是复合键,允许一个 Component 为同一个 Template 拥有多个 ComponentTemplate。
在这两种情况下,实体之间的关系映射都会发生一些变化。代替:
modelBuilder.Entity<Template>()
.HasMany(x => x.Components)
.WithMany(x => x.Templates);
在 EF Core 自动连接一个连接表的地方,您需要更明确一点:
modelBuilder.Entity<Template>()
.HasMany(x => x.TemplateComponents)
.WithOne(x => x.Template)
.IsRequired();
modelBuilder.Entity<Compoent>()
.HasMany(x => x.TemplateComponents)
.WithOne(x => x.Component)
.IsRequired();
或者它可以从 TemplateComponent 端连接。
现在,您可以访问 Template.TemplateComponents 以获取包含 Quantity 属性或同一组件的多行的组件引用集合。可以从组件中完成相同的操作。
推荐阅读
- firebase - FutureBuilder 的快照总是 null 或者没有数据
- javascript - Swup 动画
- python - Modelling 'has a' relationship
- sql-server - 将数据库中的数据提取到文本框中
- c# - C# WPF 获取选定的组合框绑定字段
- python - 在短时间内将 1d 数组与 python 中的每个 4d 数组相关联
- html - 如何在引导程序 4 中垂直对齐表单行类中的按钮
- php - 如何使用 ENC28J60 从 Ardunio Nano 向 PHP 发送数据
- sql - 如何从 Oracle 中的字符串中循环标记?
- jenkins - 我可以安排一次构建在 Jenkins 中运行吗?没有 cron 的任何解决方案