好的,我可以使用以下方法制作所需数量的钥匙流畅的API。现在可以了。
更详细:
从商业角度来说,我有一个Form
具有字段的对象,就像 html 文档中的类型一样input, choice, text, radiogroup
etc.
我更喜欢将强类型的字段数据存储在单独的表中,但表单需要知道哪些字段位于其中以维持其唯一顺序。
所以在数据库中我有表:
Form
- 包含表单的名称和描述
FormField
-(每个表格 0 到多行)包含FormId, 字段类型 and OrderNo。通过设置(表单 ID、订单号)为了独特,我保持正确的顺序。
诀窍在于类型化字段本身存储在不同的表中,例如InputField
, ChoiceField
, NumberField
我希望它们与父 FormField 行绑定在一起,如 0 或 1 到 1,并且不允许它们在删除父行时丢失。
如果是简单的父子关系,我可以使用标准 FK,但这里我有各种子表。
为了使一切保持一致,在SQL服务器我创建了一个复合PK(表单 ID、字段类型)在父级中FormField
表和 FK 为(表单 ID、字段类型)在所有子表中FieldType
设置为常数计算值(例如 0InputField
表 1 中ChileField
表等)。
因此,我对单个对象有一个很好的父子约束FormField
和多个子特定类型表。
在 EF 方法中,要制作复合 FK,您需要所有相应字段都是 Key,因此您将 [Key] 属性放在两个字段上。
但是,如果您的特定类型表需要有自己的子表(例如ChoiceField
有它的ChoiceOptions
),并且您已经有一个复合密钥,那么您需要使用现有的复合密钥或添加一个新的密钥集(仅Id场地)。
因此,我的问题是使 ChoiceField 表具有两组键:一组是复合键,用于父 FieldForm 行,第二组是简单键 - 用于 ChoiceOption 子表。
使用 Fluent API,我可以添加第二个密钥。
这是我的 EF 模型:
[Table("Form")]
public class Form : IEntity
{
[Key, Column("FormID")]
public int Id { get; set; }
[Required, StringLength(50)]
public string Name { get; set; }
public ICollection<FormField> FormFields { get; set; }
}
[Table("FormField")]
public class FormField : IEntity
{
[Key, Column("FormFieldID", Order = 0)]
public int Id { get; set; }
[Key, Column(Order = 1)]
public FieldType FieldType { get; set; }
[ForeignKey("Form")]
public int FormId { get; set; }
public int OrderNo { get; set; }
public virtual Form Form { get; set; }
public virtual AddressField AddressField { get; set; }
public virtual ChoiceField ChoiceField { get; set; }
public virtual DateTimeField DateTimeField { get; set; }
// etc
}
[Table("ChoiceField")]
public class ChoiceField : BaseField, IEntity
{
[Key, ForeignKey("FormField"), Column("FormFieldID", Order = 0)] // these keys are for parent FormField table
public int Id { get; set; }
[Key, ForeignKey("FormField"), Column(Order = 1)]
public FieldType FieldType { get; set; }
public virtual FormField FormField { get; set; }
public ICollection<ChoiceFieldOption> ChoiceFieldOptions { get; set; }
}
[Table("ChoiceFieldOption")]
public class ChoiceFieldOption : IEntity
{
[Key, Column("ChoiceFieldOptionID")]
public int Id { get; set; }
[ForeignKey("ChoiceField")] // this FK are bound to simple ChoiceField.Id key defined in fluent API
public int ChoiceFieldId { get; set; }
[Required, StringLength(50)]
public string Option { get; set; }
public int OrderNo { get; set; }
public virtual ChoiceField ChoiceField { get; set; }
}
...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Form>();
var eFormField = modelBuilder.Entity<FormField>();
var eChoiceField = modelBuilder.Entity<ChoiceField>();
// here I add a second Key for ChoiceField table
eChoiceField.HasKey(cf => new { cf.Id });
var eChoiceFieldOption = modelBuilder.Entity<ChoiceFieldOption>();
modelBuilder.Entity<AddressField>();
modelBuilder.Entity<DateTimeField>();
// ...
}