比方说,在我们的项目中,我们使用C#和MsSQL,并且我们有一个带有两列(Products
,ID
)的Name
表
一天,我们决定保存Company1
给出的产品信息,因此我们创建了一个新表ProductInfoFromCompany1
,因为它具有自定义列(ProductID
,Price
,{{ 1}})
第二天,我们同意CurrentScore
,现在我们也需要保存其数据。因此,新表-> Company2
具有不同的列(ProductInfoFromCompany2
,ProductID
,Year
)
前一天,我们同意Rating
,依此类推...
因此,我们不知道新公司提供的数据将如何。这就是为什么我们需要创建一个新表的原因,因为如果我们使用一个Company3
表,它将变得太宽且有许多空列
在Entity Framework Core中,我们有以下模型:
Details
您可以在public class ProductInfoFromCompany1
{
public int Id { get; set; }
public int ProductId { get; set; }
public decimal Price { get; set; }
public double CurrentScore { get; set; }
public Product Product { get; set; }
}
public class ProductInfoFromCompany2
{
public int Id { get; set; }
public int ProductId { get; set; }
public int Year { get; set; }
public double Rating { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
//Do we need these navigation properties in this class?
//public ProductInfoFromCompany1 ProductInfoFromCompany1 { get; set; }
//public ProductInfoFromCompany2 ProductInfoFromCompany2 { get; set; }
}
类中看到我的问题。
我们需要在Product
类中添加导航属性吗?
我要问的原因是,在我阅读的所有书籍或文档中,人们都使用导航属性,但是在这种情况下,它违反了开闭原则,因为每当我们添加新公司时,我们都需要修改Product
类。
P.S。如果我们要查询Product
数据并且有产品ProductInfoFromCompany1
,我们可以像这样从Id
开始查询
ProductInfoFromCompany1
答案 0 :(得分:2)
我们需要在
Product
类中添加导航属性吗?
您是唯一可以回答是否需要 的人。
如果问题是 EF Core 是否需要导航属性,答案是否定的。参考:Relationships - Single Navigation Property EF核心文档主题:
仅包含一个导航属性(没有反向导航,也没有外键属性)就足以具有由约定定义的关系。
事实上,EF Core流利的API和shadow属性允许在没有任何导航或FK属性的情况下定义关系。它将是多么有用的是另一个故事。要点(我读的是问题)是它们都不是强制性的。
当然,缺少导航属性会限制您可以创建的LINQ查询的类型-就像您说的那样,您不能从Product
开始查询,也不能对关联的{{1}应用过滤器},或渴望/明确/延迟加载它。
但是,如果您不需要所有这些,例如如您所说,您可以从ProductInfoFromCompany1
开始构建查询,然后省略ProductInfoFromCompany1
中的navigation属性就可以了。
答案 1 :(得分:0)
正如我在评论中提到的那样,需要进行设计更改才能实现所需的功能。 这是我的建议:
由于您的问题在于产品表的结构,因为您不知道每个公司都想存储什么作为其产品的信息,因此可以这样做:(稍后再解释)。
public class Company
{
[Key]
public int Id { get; set; }
[Display(Name = "Name")]
[Required]
public string Name { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Required]
[Display(Name = "Created date")]
[DataType(DataType.DateTime)]
public DateTime CreatedDate { get; set; }
public virtual ICollection<Product> Prodcuts { get; set; }
}
public class Product
{
[Key]
public int Id { get; set; }
[Display(Name="Name")]
[Required]
public string Name { get; set; }
[Required]
[Display(Name = "Created date")]
[DataType(DataType.DateTime)]
public DateTime CreatedDate { get; set; }
[Required]
[ForeignKey("Company")]
[Display(Name = "Company")]
public int CompanyID { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<ProductField> Fields { get; set; }
}
public class ProductField
{
[Key]
public int Id { get; set; }
[Display(Name = "Value")]
[Required]
public string Value { get; set; }
[Required]
[ForeignKey("Product")]
[Display(Name = "Product")]
public int ProductID { get; set; }
public virtual Product Product { get; set; }
[Required]
[ForeignKey("Field")]
[Display(Name = "Field")]
public int FieldID { get; set; }
public virtual Field Field { get; set; }
[Required]
[Display(Name = "Created date")]
[DataType(DataType.DateTime)]
public DateTime CreatedDate { get; set; }
}
public class Field
{
[Key]
public int ID { get; set; }
[MaxLength(100)]
[Index("ActiveAndUnique", 1, IsUnique = true)]
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "Description")]
public string Description { get; set; }
[Required]
[Display(Name = "Created date")]
[DataType(DataType.DateTime)]
public DateTime CreatedDate { get; set; }
}
代码说明:
这种方法使您可以更好地控制数据,而不必为每个产品信息创建表格。
公司: 我首先创建一个带有导航属性的公司表,该表将延迟加载与之相关的所有产品。(如果启用了延迟加载) 然后在产品表中添加一个FK来引用该公司。
字段: 由于您提到您不知道公司将拥有什么产品信息,因此可以创建一个新字段,并使用ProductField表将其链接到产品。
产品字段: 该表将在您的产品和字段之间充当“多对多”的角色,因此您可以在新产品中添加尽可能多的字段,而无需修改产品表的结构或创建新表。如果公司3需要,您也可以重复使用同一字段。
用法:
鉴于我们有一家名为 MyCompany 的公司。 MyCompany有一个名为Car的产品,需要添加到汽车中的信息是Make和Color。 我们创建两个名为Make和Color的新字段,然后在ProductField表中添加两个新条目: 第一个将具有: 字段“ Make”的ID,值“ BMW”,以及对该ID为Car的产品的引用。 我们通过引用“颜色”字段和产品“汽车”来对颜色做同样的事情。
查询: 现在,查询要比为每个公司的产品信息提供表格要简单得多。
示例:
var myProducts = _db.Products.Where(p=>p.CompanyID== "1").Include(p=>p.Fields).Tolist()
同样,这是我的看法。希望对您有所帮助。