4.4关系配置

简介: 关系配置

4.4关系配置

一对多

案例:文章和评论的关系就是一对多

publicclassArticle

{

   publiclongId { get; set; }//主键

   publicstringTitle { get; set; }//标题

   publicstringContent { get; set; }//内容

   publicList<Comment>Comments { get; set; } =newList<Comment>(); //此文章的若干条评论

}

publicclassComment

{

   publiclongId { get; set; }

   publicArticleArticle { get; set; } //对应的文章

   publicstringMessage { get; set; }

}

EF Core实体之间关系配置采用HasXXX(...).WithYYY(...)可以认为这是固定用法

HasXXX代表当前实体类和关联的另一个实体类的关系

WithYYY代表另一实体类与当前实体类的关系

例如在A实体类中定义builder.HasOne<B>(...).WithMany(...)代表A实体类对应一个B实体类,而B实体类对应多个A实体类

实体配置类

classCommentConfig : IEntityTypeConfiguration<Comment>

{

   publicvoidConfigure(EntityTypeBuilder<Comment>builder)

   {

       builder.ToTable("T_Comments");

       //只需要配置一个实体类就能确定两者的关系

       builder.HasOne<Article>(c=>c.Article).WithMany(a=>a.Comments)

           .IsRequired();

       //HasOne<Article>(c => c.Article)表示Comment类中色Article属性指向Article属性

       //WithMany(a => a.Comments)表示一个Article类对应多个Comment类,并且通过Article中的Comments属性

       //进行访问

       builder.Property(c=>c.Message).IsRequired().IsUnicode();

   }

}

生成两张表如下,注意在T_Comments表中生成了ArticleId外键,指向T_Articles中的Id

Articlea1=newArticle();

a1.Title="微软发布.NET 6大版本的首个预览";

a1.Content="微软昨日在一篇官网博客文章中宣布了 .NET 6 首个预览版本的到来。";

Commentc1=newComment() { Message="支持" };

Commentc2=newComment() { Message="微软太牛了" };

Commentc3=newComment() { Message="火钳刘明" };

a1.Comments.Add(c1);

a1.Comments.Add(c2);

a1.Comments.Add(c3);

usingTestDbContextctx=newTestDbContext();

ctx.Articles.Add(a1);//只需要加入Article就可以,会自动增加Comment对象到数据库

awaitctx.SaveChangesAsync();

关联数据的获取

Article a = ctx.Articles.Include(a => a.Comments).Single(a => a.Id == 1);

Include方法起到了关联查询作用,用它生成对其他关联实体的查询操作使用Include不仅仅能够查询到id=1的文章,也能查询到该文章所对应的评论

Articlea=ctx.Articles.Include(a=>a.Comments).Single(a=>a.Id==1);

Console.WriteLine(a.Title);

foreach (Commentcina.Comments)

{

   Console.WriteLine(c.Id+":"+c.Message);

}

关系外键属性设置

像上面案例所示,会在“多端”的T_Comments表中自动生成外键,该外键不能在Comments中直接获取,因为Comments实体类中并没用定义外键。如果有单独获取外键的需求,可以增加一个long类型的ArticleId属性,然后再关系配置上使用HasForeignKey(c=>c.ArticleId)

classCommentConfig : IEntityTypeConfiguration<Comment>

{

   publicvoidConfigure(EntityTypeBuilder<Comment>builder)

   {

       builder.ToTable("T_Comments");

       builder.HasOne<Article>(c=>c.Article).WithMany(a=>a.Comments)

           .IsRequired().HasForeignKey(c=>c.ArticleId);

       builder.Property(c=>c.Message).IsRequired().IsUnicode();

   }

}

单导航属性

上例子中,Article类中声明了comments属性,在Commennt类中声明了Article属性,可以通过任何一方获取对方信息,这叫做双向导航。

单想导航是只在“多端”声明导航属性,不用在“一端”声明

classUser

{

   publiclongId { get; set; }

   publicstringName { get; set; }//姓名

}

//请假实体类,里面涉及好多人

classLeave

{

   publiclongId { get; set; }

   publicUserRequester { get; set; }//申请者

   publicUser?Approver { get; set; } //审批者 可能为空

   publicstringRemarks { get; set; } //说明

   publicDateTimeFrom { get; set; } //开始日期

   publicDateTimeTo { get; set; } //结束日期

   publicintStatus { get; set; }//状态

}

配置类

classLeaveConfig : IEntityTypeConfiguration<Leave>

{

   publicvoidConfigure(EntityTypeBuilder<Leave>builder)

   {

       builder.ToTable("T_Leaves");

       //WithMany()没有传递参数,因为User类中没有对应Leave类的属性

       builder.HasOne<User>(l=>l.Requester).WithMany();

       builder.HasOne<User>(l=>l.Approver).WithMany();

       builder.Property(l=>l.Remarks).HasMaxLength(1000).IsUnicode();

   }

}

插入数据

Useru1=newUser { Name="杨中科" };

Leaveleave1=newLeave();

leave1.Requester=u1;

leave1.From=newDateTime(2021, 8, 8);

leave1.To=newDateTime(2021, 8, 9);

leave1.Remarks="家里三套房拆迁,回家处理";

leave1.Status=0;

usingTestDbContextctx=newTestDbContext();

ctx.Users.Add(u1);//如果单独插入u1,则不会插入leave1,因为user中没有leave的属性

ctx.Leaves.Add(leave1);//如果单独插入leave也可以,会自动插入u1,因为有指向User的属性

awaitctx.SaveChangesAsync();

一对一

一对一的关系,由于双方都是“平等”的关系,外键可以设立在任何一方,所以必须显式在一种一个实体类中声明外键属性

//案例:订单及物流信息

classOrderConfig : IEntityTypeConfiguration<Order>

{

   publicvoidConfigure(EntityTypeBuilder<Order>builder)

   {

       builder.ToTable("T_Orders");

       builder.Property(o=>o.Address).IsUnicode();

       builder.Property(o=>o.Name).IsUnicode();

       builder.HasOne<Delivery>(o=>o.Delivery).WithOne(d=>d.Order)

           .HasForeignKey<Delivery>(d=>d.OrderId);//物流类(Delivery)中的OrderId作为指向Order的外键

   }

}

多对多

实体类,学生和老师

classStudent

{

   publiclongId { get; set; }

   publicstringName { get; set; }

   publicList<Teacher>Teachers { get; set; } =newList<Teacher>();

}

classTeacher

{

   publiclongId { get; set; }

   publicstringName { get; set; }

   publicList<Student>Students { get; set; } =newList<Student>();

}

配置类,只需要在一个配置类中设定两者的关系

在一对一和一对多中,只需要在某个表中增加外键就可以,但是在多对多中,需要引入额外的数据库表来保存两张表之间的对应关系。

classStudentConfig : IEntityTypeConfiguration<Student>

{

   publicvoidConfigure(EntityTypeBuilder<Student>builder)

   {

       builder.ToTable("T_Students");

       builder.Property(s=>s.Name).IsUnicode().HasMaxLength(20);

       builder.HasMany<Teacher>(s=>s.Teachers).WithMany(t=>t.Students)

           .UsingEntity(j=>j.ToTable("T_Students_Teachers"));//使用UsingEntity来配置中间表T_Students_Teachers

   }

}

插入和查询

Students1=newStudent { Name="tom" };

Students2=newStudent { Name="lily" };

Students3=newStudent { Name="lucy" };

Students4=newStudent { Name="tim" };

Students5=newStudent { Name="lina" };

Teachert1=newTeacher { Name="杨中科" };

Teachert2=newTeacher { Name="罗翔" };

Teachert3=newTeacher { Name="刘晓艳" };

t1.Students.Add(s1);

t1.Students.Add(s2);

t1.Students.Add(s3);

t2.Students.Add(s1);

t2.Students.Add(s3);

t2.Students.Add(s5);

t3.Students.Add(s2);

t3.Students.Add(s4);

usingTestDbContextctx=newTestDbContext();

ctx.AddRange(t1, t2, t3);//是对Add的简化调用,仍然是一个一个加入

ctx.AddRange(s1, s2, s3, s4, s5);

awaitctx.SaveChangesAsync();

usingMicrosoft.EntityFrameworkCore;

usingTestDbContextctx=newTestDbContext();

foreach (vartinctx.Teachers.Include(t=>t.Students))

{

   Console.WriteLine($"老师{t.Name}");

   foreach (varsint.Students)

   {

       Console.WriteLine($"---{s.Name}");

   }

}

相关文章
|
4月前
|
架构师 测试技术 领域建模
项目管理问题之实体、命令、事件之间有什么关系
项目管理问题之实体、命令、事件之间有什么关系
|
6月前
|
开发框架 .NET C#
浅谈c和c++和c#之间的关系
浅谈c和c++和c#之间的关系
79 0
|
数据可视化 uml
UML图讲解(关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系)
UML图讲解,关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系。
3192 0
UML图讲解(关联关系,单向关联,双向关联,自关联,组合关系,依赖关系,继承关系,实现关系)
UML关系与代码的映射
UML关系与代码的映射
|
存储 编译器 C语言
C++ 基础篇之类 & 对象的关系
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。
|
容器
getChildFragmentManager和getsupportFragmentManager和getFragmentManager的关系
getChildFragmentManager和getsupportFragmentManager和getFragmentManager的关系
类之间的关系共为6种关系
类之间的关系共为6种关系
571 0
量价关系分析
量价关系分析
376 0
量价关系分析
类和类之间的关系(2)
类和类之间的关系(2)
134 0
类和类之间的关系(2)
|
uml
类和类之间的关系(1)
类和类之间的关系(1)
117 0
类和类之间的关系(1)