EFCore_一对一、一对多、多对多

一对一、一对多、多对多

何处配置:实体配置类(以一对一为例)

如何配置
一对一:HasOne().WithOne()
关系配置在任意一端均可,但需要显式地在该端对应的实体类中声明一个外键属性,并通过HasForeignKey<T>()显式指定(需要泛型以说明外键属性所在的实体类,此处无法推断类型)

internal class DeliveryConfig : IEntityTypeConfiguration<Delivery>
{
    public void Configure(EntityTypeBuilder<Delivery> builder)
    {
        builder.HasOne(d => d.TheOrder).WithOne(o => o.TheDelivery).HasForeignKey<Delivery>(d => d.OrderId);
    }
}

实体
通过Order.TheDelivery与Delivery.TheOrder构建一对一的关系(属性名无强制要求)

internal class Order
{
    public int Id { get; set; }
    public string OrderName { get; set; }
    public int OrderNumber { get; set; }
    public Delivery TheDelivery { get; set; }
}
internal class Delivery
{
    public int Id { get; set; }
    public string CompanyName { get; set; }
    public int DeliveryNumber { get; set; }
    public Order TheOrder { get; set; }
    public int OrderId { get; set; }
}

一对多:HasOne().WithMany() 或 HasMany().WithOne()
关系原则上配置在任意一端均可,但推荐配置在"多"端。此外,外键生成在"多"端对应的表,不显式声明外键属性并指定时,默认生成的字段名为"实体类名Id"

internal class CommentConfig : IEntityTypeConfiguration<Comment>
{
    public void Configure(EntityTypeBuilder<Comment> builder)
    {
        builder.HasOne(c => c.TheArticle).WithMany(a => a.Comments);
    }
}

实体不再赘述,"多"端实体类中的"一"端属性类型为List<T> 

多对多:HasMany().WithMany()
关系配置在任意一端均可,实体对应的表中不存储外键(无需,也无法调用HasForeignKey<T>()),外键存储在额外生成的中间表中,可通过UsingEntity("xxx")或UsingEntity(t=>t.ToTable("xxx"))来指定中间表名

internal class StudentConfig : IEntityTypeConfiguration<Student>
{
    public void Configure(EntityTypeBuilder<Student> builder)
    {
        builder.HasMany(s => s.Teachers).WithMany(t => t.Students).UsingEntity(e => e.ToTable("relation_student_teacher"));
    }
}

单向导航属性 

上文示例中的Order.TheDelivery与Delivery.TheOrder为双向导航属性,简而言之就是Order与Delivery都知道对方的存在,而出现仅一方知道另一方的存在时,称该方实体类中的另一方属性为单向导航属性

问:单向导航属性存在的意义是什么?
答:避免字段膨胀 与 利好数据增减
以"教师"实体为例,其对应表为"Teacher"。除了实体的基础数据,还有教师审批的表格、教师批阅的试卷等等数据与实体相关联,但若将这些数据一同储存在Teacher表中势必会导致Teacher表的字段膨胀,并且与实体相关联的数据发生变动时需要直接修改表的字段

问:如何定义单向导航属性?
答:通常单向导航属性出现在一对一 / 一对多的情况下(多对多的情况下外键储存在中间表),所以将关系配置在单向导航属性所在的实体类的配置类中,并将WithOne() / WithMany()置空即可

联表查询

var result = dbContext.Students.Include(s => s.Teachers);

注:使用Select()会隐式调用Include() 

新增数据时,数据之间存在关联,不需要对所有导航属性赋值,也不需要对所有实例Add

简而言之,EFCore能顺藤摸瓜

Article article = new() { Title = "文章标题", Text = "震惊!......", AuthorName = "汤姆" };

Comment comment_1 = new() { Content = "一楼" };
Comment comment_2 = new() { Content = "二楼" };
Comment comment_3 = new() { Content = "三楼" };

article.Comments.Add(comment_1);
article.Comments.Add(comment_2);
article.Comments.Add(comment_3);

dbContext.Articles.Add(article);

dbContext.SaveChanges();    

上述代码中,article的导航属性Comments被添加了Comment实例,令article与comment_1、comment_2、comment_3产生了关联,所以在dbContext.Articles.Add(article)时,EFCore根据article的导航属性Comments找到Comment实例,并为Comment实例的导航属性赋值(值为article),并将Comment实例一齐Add

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值