一对多
模型
Nationality(国家)数据模型(对应“一”) 因为已过国家有很多人,而一个人只能有一个国家
namespace BF.Entities.Entitys
{
/// <summary>
/// 国家
/// </summary>
public class Nationality
{
public int Id { get; set; }
/// <summary>
/// 国家名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 简称
/// </summary>
public string Abbre { get; set; }
/// <summary>
/// 人的导航属性(一个国家里面有很多人)
/// </summary>
public virtual ICollection<Person> Persons { get; set; }
}
}
Person(人)数据模型 (对应“多”)
namespace BF.Entities.Entitys
{
/// <summary>
/// 人
/// </summary>
public class Person
{
public int Id { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 所属国家国家编号
/// </summary>
public int NationalityId { get; set; }
/// <summary>
/// 国家导航属性(一个人只能属于一个国家)
/// </summary>
public virtual Nationality Nationality { get; set; }
}
}
数据模型配置文件
NationalityConfig文件
namespace BF.Entities.EntityConfig
{
class NationalityConfig:EntityTypeConfiguration<Nationality>
{
public NationalityConfig()
{
this.ToTable("T_Nationality").HasKey(r => r.Id);
this.Property(r => r.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);//设置Id是自动增长类型的
//注意:在一对多关系中,Nationality对应的是“一” 关系配置应该在“多”端进行配置,如果在“多”端进行配置了这里可以不配置
//当然配置了也没关系。
//this表示Nationality国家这个数据模型
//this.HasMany(r => r.Persons)表示一个国家中有很多人
//.WithRequired(r => r.Nationality)是跟在HasMany(r => r.Persons)后面的,表示一个只能属于一个国家
//.HasForeignKey(r => r.NationalityId)表示T_Nationality与T_Person表之间关联的外键是T_Person表中的NationalityId属性
this.HasMany(r => r.Persons).WithRequired(r => r.Nationality).HasForeignKey(r => r.NationalityId);
}
}
}
PersonConfig文件
namespace BF.Entities.EntityConfig
{
public class PersonConfig:EntityTypeConfiguration<Person>
{
public PersonConfig()
{
this.ToTable("T_Person").HasKey(r => r.Id);
this.Property(r => r.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);//设置Id是自动增长类型的
//一对多,一般是在“多”这一方进行配置
//(国家对人,一个人只能属于一个国家,而一个国家可以有多个人,所以国家是“一”,人是“多”)
//这个this就表示Person
//this.HasRequired(r => r.Nationality)表示这个人,只能一定只能属于一个国家
//his.HasRequired(r => r.Nationality).WithMany(r => r.Persons)表示这个人只能一定只能属于一个国家,而国家有多个人
//.HasForeignKey(r => r.NationalityId)表示T_Person表与T_Nationality表关联的外键是T_Person表的NationalityId属性
this.HasRequired(r => r.Nationality).WithMany(r => r.Persons).HasForeignKey(r => r.NationalityId);
}
}
}
EF上下文容器类
在OnModelCreating方法中,将数据模型配置文件加入到DbModelBuilder容器中,这样就可以使用这个配置文件了
namespace BF.Entities
{
public class BFDbContext : DbContext
{
public BFDbContext()
: base("name=ConnStr")
{
base.Database.CreateIfNotExists();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//将模型配置文件加入到DbModelBuilder中
modelBuilder.Configurations.AddFromAssembly(
Assembly.GetExecutingAssembly());
}
public DbSet<Nationality> Nationality { get; set; }
public DbSet<Person> Person { get; set; }
}
}
使用(控制器类)
namespace WebApp.Controllers
{
using System.Data.Entity;// 如果要在IQueryable接口中使用Include就如要引入它
public class HomeController : Controller
{
public ActionResult Index()
{
BFDbContext db = new BFDbContext();
Nationality cn = new Nationality() { Name = "中国", Abbre = "CN" };
Nationality us = new Nationality() { Name = "美国", Abbre = "US" };
//注意这里要给Person类的导航属性赋值,NationalityId属性不用赋值
Person cnP = new Person() { Name = "毛泽东", Age = 86, Nationality = cn };
Person usP = new Person() { Name = "克林顿", Age = 86, Nationality = us };
//如果仅仅是添加这国家的数据的话,就无法把人添加到Person表了,
//db.Nationality.Add(cn);
//db.Nationality.Add(us);
//我们应该这样做(因为cnP,和usP中已经把这两个人添加了他们的国家了,所以执行这两段代码后,T_Person和T_Nationality都会被添加数据)
db.Person.Add(cnP);
db.Person.Add(usP);
db.SaveChanges();
//Include只能用于导航属性的联合查询,他的参数是导航属性的名称
var a = db.Person.Where(r => r.Id == 1).Include("Nationality").SingleOrDefault();
var b = db.Nationality.First().Persons.ToList();
return View();
}
}
}
我们可以看到数据库中生成了三张表, __MigrationHistory表我们不用去管它(T_Nationality国家表,T_Person 人表)
T_Nationality国家表
T_Person 人表
多对多
数据模型
Teacher(老师)模型类 (多对多关系中对应“多”)一个老师可以有多个学生,而一个学生也可以有多个老师,所以Teacher属于“多”
namespace BF.Entities.Entitys
{
//老师表
public class Teacher
{
public Teacher()
{
this.Students = new HashSet<Student>();
}
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
/// <summary>
/// 老师表中有多个学生,所以是Students
/// </summary>
public virtual ICollection<Student> Students { get; set; }
}
}
Student(学生)模型类(多对多关系中对应“多”)一个老师可以有多个学生,而一个学生也可以有多个老师,所以Student也属于“多”
namespace BF.Entities.Entitys
{
//学生表
public class Student
{
public Student()
{
this.Teachers = new HashSet<Teacher>();
}
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
/// <summary>
/// 学生可以有多个老师,所以这里是Teachers
/// </summary>
public virtual ICollection<Teacher> Teachers { get; set; }
}
}
数据模型配置文件
TeacherConfig文件
namespace BF.Entities.EntityConfig
{
public class TeacherConfig : EntityTypeConfiguration<Teacher>
{
public TeacherConfig()
{
this.ToTable("T_Teacher").HasKey(r => r.Id);
this.Property(r => r.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);//设置Id是自动增长类型的
//多对多关系配置,只要在其中一方进行配置就行了。不需要两边都进行配置,所以在TeacherConfig中配置了,就不需要在StudentConfig中再进行配置了。反过来也一样(反正只配置一方,在哪方配置都行)
//this表示Teacher这个模型类,表示T_Teacher表
//this.HasMany(r => r.Students)表示老师中有多个学生
//.WithMany(r => r.Teachers)是跟在HasMany(r => r.Students)后面的,表示学生有多个老师
//Map表示关系映射
//(r => r.ToTable("T_TeacherStudentRelations")表示这两个表生成的关系映射表名称叫T_TeacherStudentRelations
//.MapLeftKey("TeacherId") 表示这个关系映射表的左边字段(第一个字段)名称叫TeacherId(因为关系映射表就两个字段)
//.MapRightKey("StudentId") 表示这个关系映射表的右边字段(第二个字段)名称叫StudentId (因为关系映射表就两个字段)
//注释:因为this表示Teacher 它在前面,所以它是左,而Student对于的就是右了。
this.HasMany(r => r.Students).WithMany(r => r.Teachers).Map(r => r.ToTable("T_TeacherStudentRelations").MapLeftKey("TeacherId").MapRightKey("StudentId"));
}
}
}
StudentConfig文件
namespace BF.Entities.EntityConfig
{
public class StudentConfig : EntityTypeConfiguration<Student>
{
public StudentConfig()
{
this.ToTable("T_Student").HasKey(r => r.Id);
this.Property(r => r.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);//设置Id是自动增长类型的
}
}
}
EF上下文容器类
在OnModelCreating方法中,将数据模型配置文件加入到DbModelBuilder容器中,这样就可以使用这个配置文件了
namespace BF.Entities
{
public class BFDbContext : DbContext
{
public BFDbContext()
: base("name=ConnStr")
{
base.Database.CreateIfNotExists();
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//将模型配置文件加入到DbModelBuilder中
modelBuilder.Configurations.AddFromAssembly(
Assembly.GetExecutingAssembly());
}
public DbSet<Teacher> Teacher { get; set; }
public DbSet<Student> Student { get; set; }
}
}
控制器中使用
namespace WebApp.Controllers
{
using System.Data.Entity;// 如果要在IQueryable接口中使用Include就如要引入它
public class HomeController : Controller
{
public ActionResult Index()
{
BFDbContext db = new BFDbContext();
Student s1 = new Student() { Name = "张三", Age = 15 };
Student s2 = new Student() { Name = "李四", Age = 16 };
Teacher t1 = new Teacher() { Name = "李老师", Age = 35 };
Teacher t2 = new Teacher() { Name = "王老师", Age = 36 };
//给张老师添加2个学生(张三,李四)
t1.Students.Add(s1);
t1.Students.Add(s2);
//王老师只有一个学生(张三)
t2.Students.Add(s1);
//添加2个老师(两个学生可以不添加,他会自动添加)
db.Teacher.Add(t1);
db.Teacher.Add(t2);
//这两段代码可以不添加,如果要这两段代码就不要上面的那两段代码
//db.Student.Add(s1);
//db.Student.Add(s2);
db.SaveChanges();
return View();
}
}
}
我们可以看到数据库中生成了4个表,__MigrationHistory表我们不用去管他(T_Student学生表,T_Teacher老师表,T_TeacherStudentRelations老师,学生关系映射表)
T_Teacher老师表
T_Student学生表
T_TeacherStudentRelations老师,学生关系映射表