赞
踩
实验环境:
实验目的:
说明:
使用“EntityFrameworkCore”是有两种方式:DBFirst和CodeFirst,小型项目可以用CodeFirst,大型项目一般用DBFirst,这里主要采用DBFirst
下面采用DBFirst实验,最后说明CodeFirst
新建表student、book、teacher、studentbook、studentinfo
他们之间存在1对多、多对多的关系:
--***************先清空具有外键的表:studentbook/studentinfo/teacher *********** if exists (select 1 from sysobjects where id = object_id('studentbook') and type = 'U') begin drop table studentbook print '已删除表:studentbook' end go if exists (select 1 from sysobjects where id = object_id('studentinfo') and type = 'U') begin drop table studentinfo print '已删除表:studentinfo' end go if exists (select 1 from sysobjects where id = object_id('teacher') and type = 'U') begin drop table teacher print '已删除表:teacher' end go --************************************** --****************<book>************** if exists (select 1 from sysobjects where id = object_id('book') and type = 'U') begin drop table book print '已删除表:book' end go create table [book] ( [id] int not null unique, [name] varchar(50) ) ALTER TABLE [book] ADD CONSTRAINT PK_gene_book_id PRIMARY KEY(id) print '已创建:book' go --****************</book>************** --****************<student>************** if exists (select 1 from sysobjects where id = object_id('student') and type = 'U') begin drop table student print '已删除表:student' end go create table [student] ( [id] int not null unique, [name] varchar(50) not null , [addr] varchar(500) , [birth] datetime , [img] image ) ALTER TABLE [student] ADD CONSTRAINT PK_gene_student_id PRIMARY KEY(id) print '已创建:student' go --****************</student>************** --****************<studentbook>************** create table [studentbook] ( [sid] int not null , [bookid] int not null ) ALTER TABLE [studentbook] ADD CONSTRAINT PK_gene_studentbook_sid_bookid PRIMARY KEY([sid],[bookid]) --************外键约束<FK_userbook_userbook>***************** ALTER TABLE studentbook ADD CONSTRAINT FK_userbook_userbook FOREIGN KEY(sid) REFERENCES test.dbo.student (id) ON DELETE NO ACTION ON UPDATE NO ACTION --************外键约束</FK_userbook_userbook>***************** --************外键约束<FK_userbook_userbook1>***************** ALTER TABLE studentbook ADD CONSTRAINT FK_userbook_userbook1 FOREIGN KEY(bookid) REFERENCES test.dbo.book (id) ON DELETE NO ACTION ON UPDATE NO ACTION --************外键约束</FK_userbook_userbook1>***************** print '已创建:studentbook' go --****************</studentbook>************** --****************<studentinfo>************** create table [studentinfo] ( [sid] int not null unique, [indate] datetime , [type] int , [desc] varchar(500) ) ALTER TABLE [studentinfo] ADD CONSTRAINT PK_gene_studentinfo_sid PRIMARY KEY(sid) --************外键约束<FK_studentinfo_student>***************** ALTER TABLE studentinfo ADD CONSTRAINT FK_studentinfo_student FOREIGN KEY(sid) REFERENCES test.dbo.student (id) ON DELETE NO ACTION ON UPDATE NO ACTION --************外键约束</FK_studentinfo_student>***************** print '已创建:studentinfo' go --****************</studentinfo>************** --****************<teacher>************** create table [teacher] ( [id] int not null unique, [name] varchar(50) not null , [bid] int not null ) ALTER TABLE [teacher] ADD CONSTRAINT PK_gene_teacher_id PRIMARY KEY(id) --************外键约束<FK_teacher_teacher>***************** ALTER TABLE teacher ADD CONSTRAINT FK_teacher_teacher FOREIGN KEY(bid) REFERENCES test.dbo.book (id) ON DELETE NO ACTION ON UPDATE NO ACTION --************外键约束</FK_teacher_teacher>***************** print '已创建:teacher' go --****************</teacher>**************
打开vs2019,新建两个.netcore控制台项目如下:
编辑dbfirst工程,添加EntityFrameworkCore包:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.10" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.10">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.10" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
</ItemGroup>
</Project>
或者使用vs安装如下:
注意:上面包的作用
- Microsoft.EntityFrameworkCore.SqlServer:efcore操作sqlserver;
- Microsoft.EntityFrameworkCore.Tools:efcore的工具包,可用来做dbfirst/codefirst
- Microsoft.Extensions.Logging.Console:将日志输出到控制台
- Microsoft.Extensions.Logging.Debug:将日志输出到vs的调试窗口
打开包管理控制台窗口:
执行命令:Scaffold-DbContext "Data Source = .;Initial Catalog = test;User Id = sa;Password = 123456;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
完成后观察项目中自动生成了的代码:
Book.cs:
using System; using System.Collections.Generic; namespace dbfirst.Models { public partial class Book { public Book() { Studentbook = new HashSet<Studentbook>(); Teacher = new HashSet<Teacher>(); } public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Studentbook> Studentbook { get; set; } public virtual ICollection<Teacher> Teacher { get; set; } } }
Student.cs
using System; using System.Collections.Generic; namespace dbfirst.Models { public partial class Student { public Student() { Studentbook = new HashSet<Studentbook>(); } public int Id { get; set; } public string Name { get; set; } public string Addr { get; set; } public DateTime? Birth { get; set; } public byte[] Img { get; set; } public virtual Studentinfo Studentinfo { get; set; } public virtual ICollection<Studentbook> Studentbook { get; set; } } }
Teacher:
using System;
using System.Collections.Generic;
namespace dbfirst.Models
{
public partial class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public int Bid { get; set; }
public virtual Book B { get; set; }
}
}
Studentbook.cs:
using System;
using System.Collections.Generic;
namespace dbfirst.Models
{
public partial class Studentbook
{
public int Sid { get; set; }
public int Bookid { get; set; }
public virtual Book Book { get; set; }
public virtual Student S { get; set; }
}
}
Studentinfo.cs:
using System; using System.Collections.Generic; namespace dbfirst.Models { public partial class Studentinfo { public int Sid { get; set; } public DateTime? Indate { get; set; } public int? Type { get; set; } public string Desc { get; set; } public virtual Student S { get; set; } } }
testContext.cs:
using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata; namespace dbfirst.Models { public partial class testContext : DbContext { public testContext() { } public testContext(DbContextOptions<testContext> options) : base(options) { } public virtual DbSet<Book> Book { get; set; } public virtual DbSet<Student> Student { get; set; } public virtual DbSet<Studentbook> Studentbook { get; set; } public virtual DbSet<Studentinfo> Studentinfo { get; set; } public virtual DbSet<Teacher> Teacher { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings. optionsBuilder.UseSqlServer("Data Source = .;Initial Catalog = test;User Id = sa;Password = 123456;"); } } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasAnnotation("ProductVersion", "2.2.6-servicing-10079"); modelBuilder.Entity<Book>(entity => { entity.ToTable("book"); entity.HasIndex(e => e.Id) .HasName("UQ__book__3213E83ED78FF78C") .IsUnique(); entity.Property(e => e.Id) .HasColumnName("id") .ValueGeneratedNever(); entity.Property(e => e.Name) .HasColumnName("name") .HasMaxLength(50) .IsUnicode(false); }); modelBuilder.Entity<Student>(entity => { entity.ToTable("student"); entity.HasIndex(e => e.Id) .HasName("UQ__student__3213E83E18FC0D17") .IsUnique(); entity.Property(e => e.Id) .HasColumnName("id") .ValueGeneratedNever(); entity.Property(e => e.Addr) .HasColumnName("addr") .HasMaxLength(500) .IsUnicode(false); entity.Property(e => e.Birth) .HasColumnName("birth") .HasColumnType("datetime"); entity.Property(e => e.Img) .HasColumnName("img") .HasColumnType("image"); entity.Property(e => e.Name) .IsRequired() .HasColumnName("name") .HasMaxLength(50) .IsUnicode(false); }); modelBuilder.Entity<Studentbook>(entity => { entity.HasKey(e => new { e.Sid, e.Bookid }) .HasName("PK_gene_studentbook_sid_bookid"); entity.ToTable("studentbook"); entity.Property(e => e.Sid).HasColumnName("sid"); entity.Property(e => e.Bookid).HasColumnName("bookid"); entity.HasOne(d => d.Book) .WithMany(p => p.Studentbook) .HasForeignKey(d => d.Bookid) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_userbook_userbook1"); entity.HasOne(d => d.S) .WithMany(p => p.Studentbook) .HasForeignKey(d => d.Sid) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_userbook_userbook"); }); modelBuilder.Entity<Studentinfo>(entity => { entity.HasKey(e => e.Sid) .HasName("PK_gene_studentinfo_sid"); entity.ToTable("studentinfo"); entity.HasIndex(e => e.Sid) .HasName("UQ__studenti__DDDFDD370E427379") .IsUnique(); entity.Property(e => e.Sid) .HasColumnName("sid") .ValueGeneratedNever(); entity.Property(e => e.Desc) .HasColumnName("desc") .HasMaxLength(500) .IsUnicode(false); entity.Property(e => e.Indate) .HasColumnName("indate") .HasColumnType("datetime"); entity.Property(e => e.Type).HasColumnName("type"); entity.HasOne(d => d.S) .WithOne(p => p.Studentinfo) .HasForeignKey<Studentinfo>(d => d.Sid) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_studentinfo_student"); }); modelBuilder.Entity<Teacher>(entity => { entity.ToTable("teacher"); entity.HasIndex(e => e.Id) .HasName("UQ__teacher__3213E83EAD9D5139") .IsUnique(); entity.Property(e => e.Id) .HasColumnName("id") .ValueGeneratedNever(); entity.Property(e => e.Bid).HasColumnName("bid"); entity.Property(e => e.Name) .IsRequired() .HasColumnName("name") .HasMaxLength(50) .IsUnicode(false); entity.HasOne(d => d.B) .WithMany(p => p.Teacher) .HasForeignKey(d => d.Bid) .OnDelete(DeleteBehavior.ClientSetNull) .HasConstraintName("FK_teacher_teacher"); }); } } }
testContext
,增加日志输出修改testContext
的OnConfiguring
方法如下:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { #warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings. optionsBuilder.UseSqlServer("Data Source = .;Initial Catalog = test;User Id = sa;Password = 123456;"); //准备依赖容器 var services = new ServiceCollection(); services.AddLogging(builder => { builder.ClearProviders(); //将日志输出到控制台 builder.AddConsole(); //将日志输出到vs的调试窗口 builder.AddDebug(); }); var provider = services.BuildServiceProvider(); //从容器中拿到日志工厂 var loggerFactory = provider.GetRequiredService<ILoggerFactory>(); //启用efcore的日志记录 optionsBuilder.UseLoggerFactory(loggerFactory); //使efcore的日志中输出敏感信息(含参数化值) optionsBuilder.EnableSensitiveDataLogging(true); } }
只需修改Program.cs即可:
using System; using System.Text; using System.Threading.Tasks; using dbfirst.Models; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace dbfirst { class Program { static void Main(string[] args) { //TestAdd(); //TestQuery(); //TestUpdate(); //TestDelete(); Console.WriteLine("Hello World!"); } private static void TestDelete() { using (testContext db = new testContext()) { var id = db.Student.Where(i => i.Name == "小明").Select(i => i.Id).FirstOrDefault(); db.Studentbook.RemoveRange(db.Studentbook.Where(i => i.Sid == id)); db.SaveChanges(); } } private static void TestUpdate() { using (testContext db = new testContext()) { Book b = db.Book.Where(i => i.Name == "外语").FirstOrDefault(); if (b != null) { b.Name = "英语"; } db.SaveChanges(); } } private static void TestQuery() { using (testContext db = new testContext()) { var set = (from stu in db.Student join b in db.Studentbook on stu.Id equals b.Sid join book in db.Book on b.Bookid equals book.Id where stu.Name.Contains("小") select new { StuName = stu.Name, stuId = stu.Id, bookName = book.Name, bookId = book.Id }); var list = set.ToList(); foreach (var i in list) { Console.WriteLine(i.bookId + ":" + i.bookName + "," + i.StuName + ":" + i.stuId); } } } private static void TestAdd() { using (testContext db = new testContext()) { //创建四名学生(小明、小红、小刚、小军) Student xiaoming = new Student() { Id = 1, Name = "小明", Birth = DateTime.Parse("1995-02-03"), Addr = "天民路28号", Img = Encoding.UTF8.GetBytes("哈哈 this is a 测试") }; Student xiaohong = new Student() { Id = 2, Name = "小红", Birth = DateTime.Parse("1998-07-03"), Addr = "顺丰路28号", Img = Encoding.UTF8.GetBytes("哈哈 this is a 测试") }; Student xiaogang = new Student() { Id = 3, Name = "小刚", Birth = DateTime.Parse("1994-07-03"), Addr = "江山28号", Img = Encoding.UTF8.GetBytes("哈哈 this is a 测试") }; Student xiaojun = new Student() { Id = 4, Name = "小军", Birth = DateTime.Parse("1995-07-03"), Addr = "江山29号", Img = Encoding.UTF8.GetBytes("哈哈 this is a 测试") }; //创建三门课(语文、数学、外语) Book yuwen = new Book() { Id = 1, Name = "语文" }; Book shuxue = new Book() { Id = 2, Name = "数学" }; Book waiyu = new Book() { Id = 3, Name = "外语" }; //创建三个老师分别教三门课 Teacher yuwenlaoshi = new Teacher() { Id = 1, Name = "语文老师", Bid = yuwen.Id }; Teacher shuxuelaoshi = new Teacher() { Id = 2, Name = "数学老师", Bid = shuxue.Id }; Teacher waiyulaoshi = new Teacher() { Id = 3, Name = "外语老师", Bid = waiyu.Id }; //给三个学生都选择语数外三门课 Studentbook xiaohongyuwen = new Studentbook() { Bookid = yuwen.Id, Sid = xiaohong.Id }; Studentbook xiaohongshuxue = new Studentbook() { Bookid = shuxue.Id, Sid = xiaohong.Id }; Studentbook xiaohongwaiyu = new Studentbook() { Bookid = waiyu.Id, Sid = xiaohong.Id }; Studentbook xiaomingyuwen = new Studentbook() { Bookid = yuwen.Id, Sid = xiaoming.Id }; Studentbook xiaomingshuxue = new Studentbook() { Bookid = shuxue.Id, Sid = xiaoming.Id }; Studentbook xiaomingwaiyu = new Studentbook() { Bookid = waiyu.Id, Sid = xiaoming.Id }; Studentbook xiaogangyuwen = new Studentbook() { Bookid = yuwen.Id, Sid = xiaogang.Id }; Studentbook xiaogangshuxue = new Studentbook() { Bookid = shuxue.Id, Sid = xiaogang.Id }; Studentbook xiaogangwaiyu = new Studentbook() { Bookid = waiyu.Id, Sid = xiaogang.Id }; Studentbook xiaojunyuwen = new Studentbook() { Bookid = yuwen.Id, Sid = xiaojun.Id }; Studentbook xiaojunshuxue = new Studentbook() { Bookid = shuxue.Id, Sid = xiaojun.Id }; Studentbook xiaojunwaiyu = new Studentbook() { Bookid = waiyu.Id, Sid = xiaojun.Id }; //给四名同学添加扩展信息 Studentinfo xiaominginfo = new Studentinfo() { Sid = xiaoming.Id, Indate = DateTime.Now, Type = 1, Desc = "一段描述" }; Studentinfo xiaojuninfo = new Studentinfo() { Sid = xiaojun.Id, Indate = DateTime.Now, Type = 1, Desc = "一段描述" }; Studentinfo xiaohonginfo = new Studentinfo() { Sid = xiaohong.Id, Indate = DateTime.Now, Type = 1, Desc = "一段描述" }; Studentinfo xiaoganginfo = new Studentinfo() { Sid = xiaogang.Id, Indate = DateTime.Now, Type = 1, Desc = "一段描述" }; db.AddRange(xiaoming, xiaogang, xiaojun, xiaohong); db.AddRange(yuwen, waiyu, shuxue); db.AddRange(yuwenlaoshi, shuxuelaoshi, waiyulaoshi); db.AddRange(xiaominginfo, xiaoganginfo, xiaojuninfo, xiaohonginfo); db.AddRange(xiaomingyuwen, xiaomingshuxue, xiaomingwaiyu); db.AddRange(xiaohongyuwen, xiaohongshuxue, xiaohongwaiyu); db.AddRange(xiaogangyuwen, xiaogangshuxue, xiaogangwaiyu); db.AddRange(xiaojunyuwen, xiaojunshuxue, xiaojunwaiyu); db.SaveChanges(); } } } }
先运行“TestAdd”添加数据,观察如下:
控制台日志输出如下:
接下来依次运行:TestQuery
、TestUpdate
、TestDelete
即可。
在dbfirst实验的基础上,完成codefirst实验,修改codefirst
工程:
添加nuget包(和dbfirst一样即可)
将dbfirst工程
中的代码拷贝到codefirst工程
中,并将命名空间修改为codefirst
修改数据库为test2
(在testContext.cs
中修改)
最终效果如下:
将codefirst
设为启动程序
在包管理平台中执行Add-Migration init
命令,如下所示:
可看到生成的迁移类和快照
在包管理平台中执行Update-Database
命令,如下所示:
观察数据库test2:
可以看到,自动建了数据库test2并且建好了表结构
首先说明dbfirst就是先建好数据库,然后使用命令Scaffold-DbContext "Data Source = .;Initial Catalog = test;User Id = sa;Password = 123456;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
将指定的数据库中所有表生成代码到指定的工程目录中去,这就结束了。
再看一下codefirst模式,在这种模式下最后不要在数据库客户端修改数据库的结构,如果想修改数据库结构,就先改代码,然后让EntityFrameworkCore工具自动去执行修改数据库结构。
codefirst一般操作流程如下:
Add-Migration init
命令生成用来执行迁移操作的代码(init是每次迁移的一个标识,可自定义)Remove-Migration
命令直接将最近的依次迁移代码删除掉Update-Database
将迁移代码应用到数据库中,此时codefirst也就完成了。codefirst涉及到的命令说明:
Add-Migration init
(注:这个过程不需要和数据库交互)Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。