EF Core模型中导航属性的必要性

时间:2019-01-18 13:38:11

标签: c# sql-server entity-framework ef-core-2.1

比方说,在我们的项目中,我们使用C#和MsSQL,并且我们有一个带有两列(ProductsID)的Name

一天,我们决定保存Company1给出的产品信息,因此我们创建了一个新表ProductInfoFromCompany1,因为它具有自定义列(ProductIDPrice,{{ 1}})

第二天,我们同意CurrentScore,现在我们也需要保存其数据。因此,新表-> Company2具有不同的列(ProductInfoFromCompany2ProductIDYear

前一天,我们同意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

2 个答案:

答案 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()

同样,这是我的看法。希望对您有所帮助。