EFCore-关系配置
EFCore-关系配置
数据库表的关系分为一对一,一对多,多对多的映射关系
在项目中,现在很少使用外键的形式来建表,都是使用逻辑外键的形式建表,并且大部分都是数据库优先
如果在实体中实现关系之后,再使用代码优先的方式推送到数据库,则会出现数据库外键的关系
一对多
文章
public class Article
{
public long Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public List<Comment> Comments { get; set; } = new List<Comment>();
}
评论
namespace 关系配置;
public class Comment
{
public long Id { get; set; }
public Article Article { get; set; }
public string Message { get; set; }
}
映射关系
public class DBContext : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseNpgsql(@"数据库链接字符串");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>(entity =>
{
entity.ToTable("Articles");
entity.Property(a => a.Title).HasMaxLength(100).IsUnicode().IsRequired();
entity.Property(a => a.Content).IsUnicode().IsRequired();
});
modelBuilder.Entity<Comment>(entity =>
{
entity.ToTable("Comments");
entity.Property(c => c.Message).IsUnicode().IsRequired();
// 使用HasOne和WithMany来建立一对多的关系
entity.HasOne<Article>(c => c.Article).WithMany(a => a.Comments);
});
}
}
总结
这种是包含数据库外键的,代码优先的形式,使用工具Migrate将实体类推送到数据库后,数据库会根据实体类关系自动创建外键
在对数据库中的表进行插入操作的时候,也就是插入评论的时候,直接插入到文章的评论List集合,EF会直接根据其关系将评论插入到评论表中,无需单独将评论插入评论表中
在对数据库中的表进行查询操作的时候,在EFCore也不会自动查询的文章中的评论的数据,也就是不会进行多表联查,但可以使用Include语句,EFCore就会将关联的对象通过连接查询的方式查到数据
var queryable = dbContext.Articles.Include(a => a.Comments).Select(a => a);
但实际项目中,很少会用这种深度耦合的关系,即数据库外键的功能,大多会在文章表中储存一个评论id,然后进行多表联查后封装为Vo将数据打包返回
对一和对多
在学习MyBatis的时候,将实体类和数据库表的关系分开来算,对于数据库来说,才有一对一,一对多,多对多的关系
而对于实体类来说,则只存在对一和对多的关系,即本身对应多个,或本身对应一个的关系
在.NET中,这种关系叫做单项导航,在建立关系时,withMany的参数不填写即可
需要注意的是,EFCore中,实体类和数据库表的关系更加的密切,在进行关系配置的时候,则不像是MyBatis那样分的清楚了
// 在“多”的这边建立关系,即在Comments中建立关系
entity.HasOne<Article>(c => c.Article).WithMany(); // 单项导航属性,即一个文章对应多个评论
多对一
一对多的关系同样可以转换为多对一的关系
public class DBContext : DbContext
{
public DbSet<Article> Articles { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseNpgsql(@"Host=172.16.22.222;Username=postgres;Password=synyi;Database=bai_study");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Article>(entity =>
{
entity.ToTable("Articles");
entity.Property(a => a.Title).HasMaxLength(100).IsUnicode().IsRequired();
entity.Property(a => a.Content).IsUnicode().IsRequired();
// 使用HasMany和WithOne来建立多对一的关系
entity.HasMany(a => Comments).WithOne(c => c.Article);
});
modelBuilder.Entity<Comment>(entity =>
{
entity.ToTable("Comments");
entity.Property(c => c.Message).IsUnicode().IsRequired();
});
}
}
注:单项导航时,需要将配置写在有导航属性那一端
一对一和多对多
和一对多的关系配置方法没有什么明显的差别
在一对一中,我们需要显示的配一个外键
在多对多中,我们需要一个关系表来反映两表之中的关系