我想先使用 EF 代码来应用现有的数据库表建模。
假设我有三个表。
项目
表。主键是ProjectId,还有ProjectName、StartDate、EndDate等其他列。技术
表。主键为TechnologyId,其他列为technologyName、Note等。ProjectTechnologyLink
。将两个表链接在一起。它具有主键 ProjectId 和 TechnologyId,它们也是外键。
ProjectTechnologyLink
中的示例数据
ProjectId TechnologyId CreatedBy CreatedDate
25 3 One 2016-01-01
100 4 One 2016-01-01
100 8 Two 2016-01-01
假设一个项目可以有多种技术,一种技术可以存在于多个项目中。
模型类是: 对于项目:
public class Project
{
public int ProjectId {get;set;}
public string ProjectName {get;set;}
...
public ICollection<ProjectTechnologyLink> ProjectTechnologyLink
}
对于技术:
public class Technology
{
public Technology()
{
ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
}
public int TechnologyId {get;set;}
public string TechnologyName {get;set;}
...
public ICollection<ProjectTechnologyLink> ProjectTechnologyLink {get;set;}
}
对于 ProjectTechnologyLink 类。
public class ProjectTechnologyLink
{
public int ProjectId {get;set;}
public int TechnologyId {get;set;}
...
public Project Project {get;set;}
public Technology Technology {get;set;}
}
然后在 OnModelCreating 方法中。
modelBuilder.Entity<ProjectTechLink>(entity =>
{
entity.HasKey(e=> new {e.ProjectId, e.TechnologyId});
entity.ToTable("ProjectTechnology", "myscheme");
entity.HasOne(x=>x.Project)
.WithMany(p=>p.ProjectTechnologyLink)
.HasForeignKey(d=>d.ProjectId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_PID");
entity.HasOne(x=>x.Technology)
.WithMany(p=>p.ProjectTechnologyLink)
.HasForeignKey(d=>d.TechnologyId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_PROJECT_TECHNOLOGY_LINK_TID");
});
我的问题是 是否适合所有代码?有时我看到人们在类中的属性之前放置一些属性。但我没有。
最佳答案
您的代码非常可以接受,应该能很好地为您服务,但让我们回顾一下为什么混合使用属性和 Fluent API。
EF 管道有三个主要点,我们可以在其中注入(inject)数据库元数据(表配置),这些包括:
- 属性符号
- 代码优先约定
- 流畅的配置 API
上面的顺序也描述了它们在管道中的处理顺序,在内部,属性对 DbContext 没有意义,直到它们被内置(或自定义)约定解析,这些约定在内部使用 Fluent API 来配置数据库上下文。
不同的场景需要并允许不同的混合,通常在 Code First 场景中,属性表示法优于大量使用 Fluent API。然而,包括级联删除或诸如此类的多对多关系的外键约束通常直接在 Fluent API 中表达,因为语法可以更简单一些,并确保没有其他约定可以否决我们在数据库中的预期实现。
Attribute notation allows your table schema to be mostly contained within the class definition, but still allows the application runtime to override the interpretations of these attributes by customising, or disabling built in conventions.
如果您的元数据可以使用属性来表示,那么您的模式的整个规范将变得更加简洁,这在需要显示结构和关系的示例中在线展示您的代码解决方案时特别有用。如果你的在线示例只需要表达关系,那么这些示例通常只会使用流利的符号。 - 如果您需要分别表达模式和关系映射,则可以实现代码示例。
如果您使用属性表示法,那么您的示例可以这样表示,并且您不需要在OnModelCreating 中添加任何额外内容:
public class Project
{
[Key]
public int ProjectId { get; set; }
public string ProjectName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; } = new HashSet<ProjectTechnologyLink>();
}
NOTE: In the above
Project
class definition I have used an inline initializer for theProjectTechnologyLink
relationship, i find this style fits in well with Attribute Notation as the default value is now also defined in close proximity with the Property, when initializers are only only defined in the constructor it is easy to forget to include an init at all or it can be hard to find the init logic in code. Now a quick "Got To Definition" will reveal the default implementation as well as any database schema related attributes without having to lookup other resources.
public class Technology
{
public Technology()
{
ProjectTechnologyLink = new HashSet<ProjectTechnologyLink>();
}
[Key]
public int TechnologyId { get; set; }
public string TechnologyName { get; set; }
...
public virtual ICollection<ProjectTechnologyLink> ProjectTechnologyLink { get; set; }
}
public class ProjectTechnologyLink
{
[Key, Column(Order = 0)]
public int ProjectId { get; set; }
[Key, Column(Order = 0)]
public int TechnologyId { get; set; }
...
[ForeignKey(nameof(ProjectId))]
public virtual Project Project { get; set; }
[ForeignKey(nameof(TechnologyId))]
public virtual Technology Technology { get; set; }
}
虚拟导航属性: 在 EF 中,将导航属性标记为虚拟 成员很重要。这将允许 EF 在生成从您的实体类继承的包装类时实现延迟加载并执行这些属性的其他优化实现。即使您不打算支持延迟加载,在其他情况下 EF 将包装您的类,并且无论哪种方式,您的数据定义类都不应该关心或知道可以做出的操作决策和根据您的上下文需要在运行时更改。
Conventions: The previous example demonstrates pure attribute notation. It is very possible to replace the default Conventions with your own for defining primary and foreign keys. Meaning it is theoretically possible to not have any attributes or Fluent notation at all. I try to discourage a pure convention based approach because it makes it a bit harder to find the configuration in a large or distributed schema definition, which is also the same argument I use to discourage a pure Fluent API approach, attributes are the logical place to document the expected usage of a table or field.
关于c# - EF 模型类是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58262622/