.net core 中使用 EFcore做ORM
文章目录
1.准备
-
安装mysql数据库
-
如果使用EF core,查阅efcore 官方文档https://docs.microsoft.com/zh-cn/ef/core/get-started/?tabs=visual-studio
-
EF core 的各种提供商https://docs.microsoft.com/zh-cn/ef/core/providers/?tabs=dotnet-core-cli
使用 Mysql的源码https://gitee.com/rush_peng/netcore-31---medium-ef-core.git源码的版本要对应,不然容易报错
使用mysql 数据库进行操作,只要装两个包就行
2.安装相应的 nuge 包
Install-Package MySql.Data.EntityFrameworkCore -Version 8.0.22
EF core 的 PMC 工具
Install-Package Microsoft.EntityFrameworkCore.Tools
Add-Migration InitialCreate #命令为迁移搭建基架
Update-Database #命令创建数据库并向其应用新的迁移
验证是否安装成功
Get-Help about_EntityFrameworkCore
_/\__
---==/ \\
___ ___ |. \|\
| __|| __| | ) \\\
| _| | _| \_/ | //|\\
|___||_| / \\\/\\
TOPIC
about_EntityFrameworkCore
SHORT DESCRIPTION
Provides information about the Entity Framework Core Package Manager Console Tools.
<A list of available commands follows, omitted here.>
3.软件包管理控制台
在实际项目中,数据模型随着功能的实现而变化:添加和删除新的实体或属性,并且需要相应地更改数据库架构,使其与应用程序保持同步。 EF Core 中的迁移功能能够以递增方式更新数据库架构,使其与应用程序的数据模型保持同步,同时保留数据库中的现有数据。
3.1迁移的过程
1.比如你刚开始创建了一个程序
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
}
2.这个时候,你需要做一个迁移:(数据库字段从无到有)
Add-Migration InitialCreate
EF Core 将在项目中创建一个名为“Migrations”的目录,并生成一些文件。 最好检查 EF Core 生成的内容,并在可能的情况下修改它,但现在我们跳过此操作。 initialCreate 是自己给此次迁移起的一个名字。
3.执行迁移
Update-Database
4.过了几天,你又修改了模型
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime CreatedTimestamp { get; set; }
}
5.执行迁移命令
Add-Migration AddBlogCreatedTimestamp
Update-Database
3.2其他的 EF Core 命令行工具
若要显示有关命令的帮助信息,请使用 PowerShell Get-Help 命令。
- Add-Migration : 添加新的迁移
- Drop-Database : 删除数据库
- Remove-Migration:删除上一次迁移 (回滚对迁移) 所做的代码更改。
- Update-Database:将数据库更新到上次迁移或指定迁移。
4.一个简单的应用实例
一个学校的数据库表,一个班级对应多个学生,一个学生,对应一个班级
4.1建表
DbsetClassrooms 一定要加 pubulic
public class School:DbContext
{
public DbSet<Classroom> Classrooms { get; set; } //Classrooms 是表名字
public DbSet<Student> Students { get; set; } //Students 是表名字
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseMySQL
("server=localhost;database=studentmessage;user=root;password=123456");
//连接本地数据库
// options.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=test02;Trusted_Connection=True;MultipleActiveResultSets=true");
}
public class Classroom
{
public int ClassroomId { get; set; } //带有id 的默认就是主键
public string address { get; set; }
public List<Student> Students { get; set; } = new List<Student>(); //导航属性,实际的数据库中并没有
}
public class Student
{
public int StudentId { get; set; }
public string Gender { get; set; }
public int ClassroomId { get; set; }
public Classroom classroom { get; set; } //导航属性,实际的数据库中并没有
}
4.2 增删改查操作
using (var db = new SchoolDbContext())
{
//create
Console.WriteLine("添加一个班级");
db.Add(new Classroom { address = "教学楼一楼", ClassroomId = 4 }); //注意 相同的 add 命令,只能执行一次。
db.Add(new Classroom { address = "教学楼二楼", ClassroomId = 3 });
db.SaveChanges();
//read
Console.WriteLine("读一个班级的信息");
var classroomdb01 = db.Classrooms
.OrderBy(b => b.ClassroomId)
.First();
Console.WriteLine(classroomdb01.ClassroomId);
//update
//更新的是上边选出来的人的
classroomdb01.address = "教学楼楼顶";
db.SaveChanges();
classroomdb01.Students.Add(
new Student { Name = "张三", Gender = "男", StudentId = 1, ClassroomId = 1 }
);
db.SaveChanges();
//delete
db.Remove(classroomdb01);
db.SaveChanges();
}
5.指定表之间的关系
参考文献1对这块写的不错,可以看看
目前 EF 不能直接实现多对多的关系,需要用个中间类做调整。两边的导航属性是数组,中间类的两个导航属性是实体(可以看看下边 6复杂点的例子)
- 声明一个主体实体(主表)与依赖实体(从表)
- 指定modelBuilder.Entity,T是依赖实体或者主体实体
- HasOne 或 HasMany 标识依赖实体中(即正在配置的)的导航属性
- WithOne 或 WithMany 来标识反向实体的导航属性
- HasForeignKey中标识外键(从表)
看下边的例子:
配置多对一的关系,可以使用两种写法,这里City是依赖实体(从表),其中包含外键ProvinceId,Province是主体实体
//第一种 modelBuilder.Entity<依赖主体>
modelBuilder.Entity<City>().HasOne(x => x.Province).
WithMany(x => x.Cities).HasForeignKey(x => x.ProvinceId);
//第二种 modelBuilder.Entity<实体主体>
modelBuilder.Entity<Province>().HasMany(x => x.Cities).
WithOne(x => x.Province).HasForeignKey(x => x.ProvinceId);
6.一个复杂点的例子
- 创建数据库上下文
- 上下文依赖注入使用
- 添加种子数据
- 创建表的时候指定表明
前期准备,建立学生 . 课程. 选课 三个类!
public class Course
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int CourseID { get; set; }
public string Title { get; set; }
public int Credits { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
public class Student
{
public int ID { get; set; }
public string LastName { get; set; }
public string FirstMidName { get; set; }
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
public enum Grade
{
A, B, C, D, F
}
public class Enrollment
{
public int EnrollmentID { get; set; }
public int CourseID { get; set; }
public int StudentID { get; set; }
public Grade? Grade { get; set; }
public Course Course { get; set; }
public Student Student { get; set; }
}
1.创建数据库上下文
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("TableCourse"); //指定表的名字
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
//添加种子数据
modelBuilder.Entity<Student>().HasData(
new Student {ID=1, FirstMidName = "Carson", LastName = "Alexander", EnrollmentDate = DateTime.Parse("2005-09-01") }
); }
}
2.依赖注入使用上下文:
services.AddDbContext<SchoolContext>(options =>
options.UseMySQL(Configuration.GetConnectionString("DefaultConnection")));
// GetConnectionString 按 F12 进去,他就是找一个名叫 ConnectionStrings 的字符串
3.在appsettings.json 文件里添加链接字符串
"ConnectionStrings": {
"mysqlConnection": "server=localhost;database=progress_track;user=root;password=123456",
"aliyunMySql": "server=rm.aliyuncs.com;port=3306;database=mysql;user=zhao;password=xxxxxxx",
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=progress_track;Trusted_Connection=True;MultipleActiveResultSets=true"
},
4.在需要用到数据库的地方,直接依赖注入引用就可以
注意一下异步的用法
public class StudentController : ControllerBase
{
private readonly SchoolContext schoolContext;
private int dex = 2;
public StudentController(SchoolContext schoolContext)
{
this.schoolContext = schoolContext;
}
[HttpGet("add")]
public async Task<int> AddCreateAsync() //只要里面有异步的思想,就要使用 Task
{
var students = new Student[]
{
new Student{FirstMidName="Carson",LastName="Alexander",EnrollmentDate=DateTime.Parse("2005-09-01")},
new Student{FirstMidName="Meredith",LastName="Alonso",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Arturo",LastName="Anand",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Gytis",LastName="Barzdukas",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Yan",LastName="Li",EnrollmentDate=DateTime.Parse("2002-09-01")},
new Student{FirstMidName="Peggy",LastName="Justice",EnrollmentDate=DateTime.Parse("2001-09-01")},
new Student{FirstMidName="Laura",LastName="Norman",EnrollmentDate=DateTime.Parse("2003-09-01")},
new Student{FirstMidName="Nino",LastName="Olivetto",EnrollmentDate=DateTime.Parse("2005-09-01")}
};
foreach (var student in students)
{
student.ID = ++dex;
schoolContext.Students.Add(student);
}
var resut = await schoolContext.SaveChangesAsync();
return resut;
}
}
7.忽略某一个属性
如何在 Entity 中有,但是不在数据库中建立相应的字段
modelBuilder.Entity<Company>().Ignore(x=>x.testIgnore)
8.多对多
以city和company为例,一个city会有多个company,一个company在多个city都有多个分company
using System;
using Microsoft.EntityFrameworkCore;
namespace ASPNetEFFCore.Models
{
public class MyContext:DbContext
{
public MyContext(DbContextOptions<MyContext> options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder){
//使用x.CityId,x.CompanyId生成 cityCompany的联合主键
//执行数据库迁移
modelBuilder.Entity<CityCompany>().HasKey(x => new{x.CityId,x.CompanyId});
//配置多对多 ,就是两个一对多,可以不写
modelBuilder.Entity<CityCompany>().HasOne(x => x.City).WithMany(x=> x.CityCompany).HasForeignKey(x=>x.CityId);
modelBuilder.Entity<CityCompany>().HasOne(x => x.Company).WithMany(x=> x.CityCompany).HasForeignKey(x=>x.CompanyId);
}
public DbSet<City> Cities { get; set; }
public DbSet<CityCompany> cityCompanies {get;set;}
}
public class City
{
public City()
{
CityCompany = new List<CityCompany>();
}
public int Id { get; set; }
public string Name { get; set; }
public string AreaCode { get; set; }
public int ProvinceId { get; set; }
public Province Province { get; set; }
//多对多映射
public List<CityCompany> CityCompany {get;set;}
}
public class Company
{
public Company()
{
CityCompany = new List<CityCompany>();
}
public int Id {get;set;}
public string Name {get;set;}
public DateTime EstablishDate {get;set;}
public string LegalPerson {get;set;}
//多对多映射
public List<CityCompany> CityCompany {get;set;}
}
//多对多中间model
public class CityCompany
{
public int CityId {get;set;}
public City City{get;set;}
public int CompanyId {get;set;}
public Company Company {get;set;}
}
}
参考文献:
[1]https://blog.csdn.net/weixin_41372626/article/details/104740176
[2]微软官方网站