十年河东,十年河西。莫欺少年穷
学无止境,精益求精
最近再看Net5相关视频,看的过程中就想把看到的知识通过博客展示出来,因此就有了这篇博客
之前项目中用的DbFirst ,本篇开启CodeFirst,按照微软官方提供的说法,是希望大家都用CodeFirst
1、CodeFirst
1.1、新建控制台项目并引入如下程序集
Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.Tools
1.2、编写实体
实体对应的是数据库的表
public class Book { public long id { get; set; } [Description("书的名称")] public string Title { get; set; } public DateTime Pubdate { get; set; } public double Price { get; set; } } public class Person { public long id { get; set; } [Description("姓名")] public string Name { get; set; } public string Age { get; set; } public string Address { get; set; } }
1.3、绑定实体和数据表的关系
public class BookConfig : IEntityTypeConfiguration<Book> { public void Configure(EntityTypeBuilder<Book> builder) { builder.ToTable("T_Books"); } } public class PersonConfig : IEntityTypeConfiguration<Person> { public void Configure(EntityTypeBuilder<Person> builder) { builder.ToTable("T_Persons"); builder.Property("Name").HasMaxLength(50).IsRequired(true).HasComment("我是字段备注:姓名"); } }
意味着Book实体对应的表为 T_Books
builder.Property 声明字段的一些规则,例如长度最大为50【HasMaxLength(50)】、字段为非空字段【IsRequired(true)】、设定字段备注【HasComment】等
除了上述的方法外,我们还可以通过数据注解的方式完成字段最大长度设定、是否能为Null等设置,例如:
[Table("T_Cats")] public class Cat { //当遇到 Int、long、ShortInt、Guid类型时,根据约定,该字段会被设置为主键 public Guid catId { get; set; } [Required] [MaxLength(50)] public string catName { get; set; } [MaxLength(50)] public string sex { get; set; } }
这种方式虽说简单,但,还是建议大家使用IEntityTypeConfiguration<>的方式进行绑定
例如有这么个变态需求,当使用MySQL数据时,希望在数据库中表名为M_Cats,当在SQLServer数据库中是希望表名为T_Cats,那么如果你使用数据注解的方式就无法完成这个工作,使用IEntityTypeConfiguration<>的方式则可以在void Configure(EntityTypeBuilder<Person> builder)方法中写相关的逻辑代码。
1.4、创建数据库上下文
public class wechatDbContext : DbContext { public DbSet<Book> Books { get; set; } public DbSet<Person> Persons { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer("Data Source=LAPTOP-84R6S0FB;Initial Catalog=wechat;Integrated Security=True"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); //从当前程序集命名空间加载所有的IEntityTypeConfiguration modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
OnConfiguring 方法初始化数据库链接字符串
OnModelCreating 从当前程序集命名空间加载所有的IEntityTypeConfiguration绑定的实体
1.5、通过程序包控制台,生成数据库
Add-Migration initDb -- Update-Database
Add-Migration 的语法为 Add-Migration + 备注,每次备注不允许一样
Update_DataBase 生成或更新数据库
当然,如果在实际编码中修改字段的长度、字段类型,新增字段、删除字段等操作后,需要执行 Add-Migration 和 Update-DataBase ,执行后数据库才会做出响应的改变。
1.6、简单测试
由于DbContext 继承了 IDisposable 、因此在编程时,我们需要使用Using ,这样做是为了能够及时的释放占用的资源。
简单测试如下:
using System; using System.Linq; using System.Threading.Tasks; namespace EfCore { internal class Program { static async Task Main(string[] args) { var tsk_1 = add(); var tsk_2 = update(await tsk_1); var tsk_3 = delete(await tsk_1); await tsk_2; await tsk_3; Console.WriteLine("执行完毕"); Console.Read(); } static async Task<int> add() { using (wechatDbContext context = new wechatDbContext()) { Book bok = new Book(); bok.Title = "钢铁是怎么练成的"; bok.Price = 180; bok.Pubdate = DateTime.Now; context.Books.Add(bok); Book bok2 = new Book(); bok2.Title = "平凡的世界"; bok2.Price = 110; bok2.Pubdate = DateTime.Now; context.Books.Add(bok2); return await context.SaveChangesAsync(); } } static async Task update(int addnum) { using (wechatDbContext context = new wechatDbContext()) { var ef = context.Books.Where(A => A.Title == "平凡的世界").FirstOrDefault(); ef.Price = 122; await context.SaveChangesAsync(); } } static async Task delete(int addNum) { using (wechatDbContext context = new wechatDbContext()) { var ef = context.Books.Where(A => A.Title == "钢铁是怎么练成的").FirstOrDefault(); context.Books.Remove(ef); await context.SaveChangesAsync(); } } } }
@天才卧龙的bolero