使用 Entity Framework Code First 和 Fluent API 配置许多一对一关系
Configuring many One-To-One relationships with Entity Framework Code First and Fluent API
我有一个糟糕的数据库模型(在 MySQL 中,虽然我认为这不重要)是别人设计的,所以我坚持使用它,但想与 Entity Framework 一起使用无论如何:
数据库
项目
ASSET_ID* ASSET_NAME FIELDS_ID
1 Cat 1
2 Dog 2
3 Fish 3
项目字段
ID* CUSTOMFIELD1ID CUSTOMFIELD2ID CUSTOMFIELD3ID
1 1001 1002 1003
2 1004 1005 1006
3 1007 1008 1009
字段
ID* STRINGVAL
1001 Meow Mix
1002 House
1003 5lbs
1004 Kibble
1005 Yard
1006 30lbs
1007 Fish Food
1008 Tank
1009 0.5 ounces
*表示table的PK
目标
最终,我正在尝试配置关系,这样我就可以获得这样的自定义数据:
Item item = GetItem(1);
item.Food.ToString(); // Output: meow mix
item.Place.ToString(); // Output: house
item.Weight.ToString(); // Output: 5 lbs
...等但老实说,我现在会接受这个:
Item item = GetItem(1);
Item.ItemFields.CustomField3.Value // Output: 5 lbs
Item item = GetItem(2);
Item.ItemFields.CustomField2.Value // Output: Yard
Item item = GetItem(3);
Item.ItemFields.CustomField1.Value // Output: Fish Food
到目前为止的解决方案
到目前为止我得到了这个:
一对一:项目 - 项目字段
modelBuilder.Entity<Item>()
.HasRequired(x => x.ItemFields)
.WithRequiredPrincipal(y => y.Item);
但是将 ItemFields.CustomField1ID 映射到 Field.ID 呢?
是否可以先使用 EF 代码配置这样的关系?我很困惑这是一对一还是一对多……我认为它实际上是许多一对一(如果这有意义的话)。
有什么建议吗?
我可能已经明白了。我将 ItemFields class 编辑为如下所示:
public class ItemFields
{
public int Id { get; set; }
public int CUSTOMFIELD1ID { get; set; }
public virtual Field CustomField1 { get; set; }
然后配置这些关系:
modelBuilder.Entity<Item>()
.HasRequired(x => x.CustomField1)
.WithMany()
.HasForeignKey(x => x.CUSTOMFIELD01_ID);
modelBuilder.Entity<Item>()
.HasRequired(x => x.CustomField2)
.WithMany()
.HasForeignKey(x => x.CUSTOMFIELD02_ID);
它似乎奏效了,但老实说我并不完全明白为什么。理想情况下,我仍然希望将它们映射到对用户更友好的 classes.
我想你同意在这种情况下我们实际上是一对多的关系:一个项目有几个字段,table ItemFields 是代理项。我建议您执行重构并只创建两个 table:项目和字段。在字段 table 中将添加列类型 - 类似于 CUSTOMFIELD1ID(2ID,3ID) 和直接引用到项目 table 的外键。在项目 class 中添加了属性:食物、地点和重量。它们不会映射到列,但您可以按照您在问题中指定的方式使用它们来访问特定字段(查看实施部分):
型号:
public enum CustomType
{
Food,
Place,
Weight
}
public class Item
{
public int ID { get; set; }
public string ASSET_NAME { get; set; }
public virtual ICollection<Field> fields { get; set; }
[NotMapped]
public Field Food { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Food).FirstOrDefault(); } }
[NotMapped]
public Field Place { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Place).FirstOrDefault(); } }
[NotMapped]
public Field Weight { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Weight).FirstOrDefault(); } }
}
public class Field
{
public int ID { get; set; }
public string STRINGVAL { get; set; }
public CustomType Type { get; set; }
public virtual Item Item { get; set; }
}
表格:
实施:
var db = new DataContext();
var item = db.Items.Include("fields").Where(x => x.ID == 1).First();
var Food = item.Food;
var Place = item.Place;
var Weight = item.Weight;
我有一个糟糕的数据库模型(在 MySQL 中,虽然我认为这不重要)是别人设计的,所以我坚持使用它,但想与 Entity Framework 一起使用无论如何:
数据库
项目
ASSET_ID* ASSET_NAME FIELDS_ID
1 Cat 1
2 Dog 2
3 Fish 3
项目字段
ID* CUSTOMFIELD1ID CUSTOMFIELD2ID CUSTOMFIELD3ID
1 1001 1002 1003
2 1004 1005 1006
3 1007 1008 1009
字段
ID* STRINGVAL
1001 Meow Mix
1002 House
1003 5lbs
1004 Kibble
1005 Yard
1006 30lbs
1007 Fish Food
1008 Tank
1009 0.5 ounces
*表示table的PK
目标
最终,我正在尝试配置关系,这样我就可以获得这样的自定义数据:
Item item = GetItem(1);
item.Food.ToString(); // Output: meow mix
item.Place.ToString(); // Output: house
item.Weight.ToString(); // Output: 5 lbs
...等但老实说,我现在会接受这个:
Item item = GetItem(1);
Item.ItemFields.CustomField3.Value // Output: 5 lbs
Item item = GetItem(2);
Item.ItemFields.CustomField2.Value // Output: Yard
Item item = GetItem(3);
Item.ItemFields.CustomField1.Value // Output: Fish Food
到目前为止的解决方案
到目前为止我得到了这个:
一对一:项目 - 项目字段
modelBuilder.Entity<Item>()
.HasRequired(x => x.ItemFields)
.WithRequiredPrincipal(y => y.Item);
但是将 ItemFields.CustomField1ID 映射到 Field.ID 呢?
是否可以先使用 EF 代码配置这样的关系?我很困惑这是一对一还是一对多……我认为它实际上是许多一对一(如果这有意义的话)。
有什么建议吗?
我可能已经明白了。我将 ItemFields class 编辑为如下所示:
public class ItemFields
{
public int Id { get; set; }
public int CUSTOMFIELD1ID { get; set; }
public virtual Field CustomField1 { get; set; }
然后配置这些关系:
modelBuilder.Entity<Item>()
.HasRequired(x => x.CustomField1)
.WithMany()
.HasForeignKey(x => x.CUSTOMFIELD01_ID);
modelBuilder.Entity<Item>()
.HasRequired(x => x.CustomField2)
.WithMany()
.HasForeignKey(x => x.CUSTOMFIELD02_ID);
它似乎奏效了,但老实说我并不完全明白为什么。理想情况下,我仍然希望将它们映射到对用户更友好的 classes.
我想你同意在这种情况下我们实际上是一对多的关系:一个项目有几个字段,table ItemFields 是代理项。我建议您执行重构并只创建两个 table:项目和字段。在字段 table 中将添加列类型 - 类似于 CUSTOMFIELD1ID(2ID,3ID) 和直接引用到项目 table 的外键。在项目 class 中添加了属性:食物、地点和重量。它们不会映射到列,但您可以按照您在问题中指定的方式使用它们来访问特定字段(查看实施部分):
型号:
public enum CustomType
{
Food,
Place,
Weight
}
public class Item
{
public int ID { get; set; }
public string ASSET_NAME { get; set; }
public virtual ICollection<Field> fields { get; set; }
[NotMapped]
public Field Food { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Food).FirstOrDefault(); } }
[NotMapped]
public Field Place { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Place).FirstOrDefault(); } }
[NotMapped]
public Field Weight { get { return fields == null ? null : fields.Where(x => x.Type == CustomType.Weight).FirstOrDefault(); } }
}
public class Field
{
public int ID { get; set; }
public string STRINGVAL { get; set; }
public CustomType Type { get; set; }
public virtual Item Item { get; set; }
}
表格:
var db = new DataContext();
var item = db.Items.Include("fields").Where(x => x.ID == 1).First();
var Food = item.Food;
var Place = item.Place;
var Weight = item.Weight;