十年河东十年河西,莫欺少年穷
学无止境,精益求精
codefirst 中如果要建立两张表的主外键关系,该如何操作呢?
在EfCore 中实体关系的配置主要有3中模式
一对一 :HasOne(....).WithOne(....)
一对多 :HasOne(....).WithMany(....)
多对多 :HasMany(....).WithMany(....)
1、一对多关系【双向导航属性】
项目中新建两张表,一张为新闻表,一张为评论表,一篇新闻对应多个评论
//文章 public class Article { public long id { get; set; } public string title { get; set; } public string info { get; set; } public DateTime pubdate { get; set; } public List<Comment> comments { get; set; } = new List<Comment>(); } //评论 public class Comment { public long id { get; set; } public string uname { get; set; } public string message { get; set; } public Article articleId { get; set; } }
1.1、配置一对多关系
(方式1)
public class ArticleConfig : IEntityTypeConfiguration<Article> { public void Configure(EntityTypeBuilder<Article> builder) { builder.ToTable("T_Articles"); builder.HasMany<Comment>(A => A.comments).WithOne(A => A.articleId); } } public class CommentConfig : IEntityTypeConfiguration<Comment> { public void Configure(EntityTypeBuilder<Comment> builder) { builder.ToTable("T_Comments"); builder.Property("uname").HasMaxLength(50).IsRequired(true).HasComment("评论者姓名"); } } public class wechatDbContext : DbContext { public DbSet<Article> Articles { get; set; } public DbSet<Comment> Comments { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=demo1;Integrated Security=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
builder.HasMany<Comment>(A => A.comments).WithOne(A => A.articleId);
(方式2)
builder.HasOne<Article>(A => A.articleId).WithMany(A => A.comments);
1.2、显式指定外键列
//文章 一对多 public class Article { public long id { get; set; } public string title { get; set; } public string info { get; set; } public DateTime pubdate { get; set; } public List<Comment> Comments { get; set; } = new List<Comment>(); } //评论 一对多 public class Comment { public long id { get; set; } public string uname { get; set; } public string message { get; set; } public long articleId { get; set; } public Article article { get; set; } }
配置关系并指定外键列
public class ArticleConfig : IEntityTypeConfiguration<Article> { public void Configure(EntityTypeBuilder<Article> builder) { builder.ToTable("T_Articles"); //显式指定外键列 builder.HasMany<Comment>(A => A.Comments).WithOne(A => A.article).HasForeignKey(A => A.articleId); } }
建议使用这种显式指定外键列的方式进行
2、配置一对一关系
假设一篇文章只允许一条评论
实体模型对应关系如下【一对一关系需要显示指定外键】:
//文章 一对一 public class Article { public long id { get; set; } public string title { get; set; } public string info { get; set; } public DateTime pubdate { get; set; } public Comment comment { get; set; } } //评论 一对一 public class Comment { public long id { get; set; } public string uname { get; set; } public string message { get; set; } public long articleId { get; set; } public Article article { get; set; } public long acticleId { get; set; } }
(方式一)
public class ArticleConfig : IEntityTypeConfiguration<Article> { public void Configure(EntityTypeBuilder<Article> builder) { builder.ToTable("T_Articles"); } } public class CommentConfig : IEntityTypeConfiguration<Comment> { public void Configure(EntityTypeBuilder<Comment> builder) { builder.ToTable("T_Comments"); builder.Property("uname").HasMaxLength(50).IsRequired(true).HasComment("评论者姓名"); builder.HasOne<Article>(A => A.article).WithOne(d => d.comment).HasForeignKey<Comment>(A => A.acticleId); } } public class wechatDbContext : DbContext { public DbSet<Article> Articles { get; set; } public DbSet<Comment> Comments { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=demo2;Integrated Security=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
builder.HasOne<Article>(A => A.article).WithOne(d => d.comment).HasForeignKey<Comment>(A => A.acticleId);
(方式二)
builder.HasOne<Comment>(A => A.comment).WithOne(d => d.article).HasForeignKey<Comment>(A => A.acticleId);
3、配置多对多关系
一个老师有多个学生,一个学生有多个老师
//老师 多对多 public class Teacher { public long id { get; set; } public string tname { get; set; } public List<Student> students { get; set; } } //学生 多对多 public class Student { public long id { get; set; } public string sname { get; set; } public List<Teacher> teachers { get; set; } }
(方式一)
public class ArticleConfig : IEntityTypeConfiguration<Teacher> { public void Configure(EntityTypeBuilder<Teacher> builder) { builder.ToTable("T_Teachers"); //T_Students_Teachers 为中间表 在数据库中 多对多必须存在中间表 builder.HasMany<Student>(A => A.students).WithMany(d => d.teachers).UsingEntity(A => A.ToTable("T_Students_Teachers")); } } public class CommentConfig : IEntityTypeConfiguration<Student> { public void Configure(EntityTypeBuilder<Student> builder) { builder.ToTable("T_Studentss"); // builder.HasMany<Teacher>(A => A.teachers).WithMany(d => d.students).UsingEntity(A => A.ToTable("T_Students_Teachers")); } } public class wechatDbContext : DbContext { public DbSet<Teacher> teachers { get; set; } public DbSet<Student> students { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=demo4;Integrated Security=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
//T_Students_Teachers 为中间表名称 在数据库中 多对多必须存在中间表 builder.HasMany<Student>(A => A.students).WithMany(d => d.teachers).UsingEntity(A => A.ToTable("T_Students_Teachers"));
(方式二)
public class CommentConfig : IEntityTypeConfiguration<Student> { public void Configure(EntityTypeBuilder<Student> builder) { builder.ToTable("T_Studentss"); builder.HasMany<Teacher>(A => A.teachers).WithMany(d => d.students).UsingEntity(A => A.ToTable("T_Students_Teachers")); } }
4、一对多关系配置【单向导航】
使用场景,
假设我们有用户表、请假表、离职表、入职表、婚假表等,其他表都需要使用到用户表,如果此时我们使用双向导航属性,则会使用户表过于复杂,因此,此时需要单向导航属性
//文章 一对多[单向导航] public class Article { public long id { get; set; } public string title { get; set; } public string info { get; set; } public DateTime pubdate { get; set; } } //评论 一对多[单向导航] public class Comment { public long id { get; set; } public string uname { get; set; } public string message { get; set; } public long articleId { get; set; } public Article article { get; set; } }
此时,Article 无需引用评论表
public class ArticleConfig : IEntityTypeConfiguration<Article> { public void Configure(EntityTypeBuilder<Article> builder) { builder.ToTable("T_Articles"); } } public class CommentConfig : IEntityTypeConfiguration<Comment> { public void Configure(EntityTypeBuilder<Comment> builder) { builder.ToTable("T_Comments"); //显式指定外键列 builder.HasOne<Article>(A => A.article).WithMany().HasForeignKey(A => A.articleId); } } public class wechatDbContext : DbContext { public DbSet<Article> Articles { get; set; } public DbSet<Comment> Comments { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=demo1;Integrated Security=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
//单向导航属性、并显式指定外键列 builder.HasOne<Article>(A => A.article).WithMany().HasForeignKey(A => A.articleId);
以上就是CodeFitst 配置一对一 、一对多、多对多的方式
@天才卧龙的博科人