4webapi创建EFCore框架的CodeFirst模式
使用工具:vs2019(基于.net5)
1. 将ef框架创建在类库里
①选择asp.net Core WebApi项目
②框架vs2019最高支持net5
③新建一个net5的类库并创建一个EFCore上下文对象类
④通过nutget包管理器安装如下两个包
一个是EFCore的,一个是用于将领域模型的实体映射到数据库中的。
注意,因为这个webapi项目是net5.0的,所以这两个包最好选低版本的安装,比如5.0,否则会不兼容
⑤在Models里设计好表
字段的限制可以在上下文对象里限制,这样逻辑比较清晰。
public class User
{
public int Id { get; set; }
[Required, StringLength(maximumLength: 40), Column(TypeName = "varchar")]
public string Email { get; set; }
public string UserName { get; set; }
}
⑥回到上下文对象里,进行配置
上下文对象必须基础DbContext类,重写里面的方法,
public class EfCoreDemoContext:DbContext
{
public EfCoreDemoContext()
{
}
public EfCoreDemoContext(DbContextOptions options):base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//设置连接字符串(也可以从配置项里读取)
optionsBuilder.UseSqlServer("server=.;database=TestDb;uid=sa;pwd=123456");
}
//该方法是在设计字段时给字段添加限制,这样可以不用在领域模型的类里加上特性,这样更加直观看到每张表的字段的限制。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//设置User类的UserName属性的长度和不能为空
modelBuilder.Entity<User>().Property(m => m.UserName).IsRequired().HasMaxLength(25).HasComment("用户名");
base.OnModelCreating(modelBuilder);
}
//该属性名就是映射到数据库里的表名
public DbSet<User> Users { get; set; }
}
⑦在Models右键打开终端
全局安装ef工具
dotnet tool install --global dotnet-ef
首次使用数据库迁移,创建迁移日志
dotnet ef migrations add init
会创建一个快照文件夹,里面存迁移日志
添加一个迁移日志
dotnet ef migrations add change_1
然后即可进行迁移
dotnet ef database update
因为第一次是要进行数据库迁移创建数据库,所以,数据库连接字符串先写死。后续通过webapi项目访问该类库操作ef时,可以选择将连接字符串写在配置文件里。
首先创建一个静态类在类库里,方便类库读取webapi项目的配置文件
namespace Models
{
public static class ConfigurationHelper
{
private static IConfiguration _config;
public static void Configure(IConfiguration config)
{
_config = config;
}
//根据配置文件键读取对应的值
public static string GetConfigValueByKey(string key)
{
var value = _config.GetConnectionString(key);
if (value == null)
{
return "";
}
return value;
}
}
}
然后修改山下文对象的配置重写的OnConfiguring方法
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//设置连接字符串(也可以从配置项里读取)
optionsBuilder.UseSqlServer(ConfigurationHelper.GetConfigValueByKey("SchoolContext"));
}
然后趣webapi项目的appsettings.json配置文件里添加数据库连接字符串配置
"ConnectionStrings": {
"SchoolContext": "Server=.;Database=TestDb;uid=sa;password=123456"
}
创建好后webapi里添加Models项目的引用即可操作上下文对象了
在webapi项目的Startup.cs类的构造函数里注入类库里的静态类ConfigurationHelper需要的IConfiguration接口的具体对象
public Startup(IConfiguration configuration)
{
Configuration = configuration;
ConfigurationHelper.Configure(configuration);
}
在webapi项目的Startup.cs类的ConfigureServices里进行构造函数注入,把eef上下文对象通过构造函数注入给控制器
services.AddScoped<EfCoreDemoContext>();
或
services.AddDbContext<EfCoreDemoContext>();
添加一个HomeController控制器,在该控制器里即可调用上下文对象操作数据库的数据了。
namespace WebApiDemo.Controllers
{
[Route("/[controller]")]
[ApiController]
public class HomeController : ControllerBase
{
private EfCoreDemoContext _efCoreDemoContext;
public HomeController(EfCoreDemoContext efCoreDemoContext)
{
_efCoreDemoContext = efCoreDemoContext;
}
[HttpGet]
public void GetUser()
{
var user= _efCoreDemoContext.Users.FirstOrDefault(m=>m.Email=="123");
}
}
}
运行调用该接口即可插入数据了
2. 上面是通过将webapi项目的IConfiguration接口的对象传给类库,然后类库进行调用读取webapi的项目文件的,比较麻烦,我们可以直接在webapi项目里配置好上下文对象的信息,然后将配置好的上下文对象传给类库的上下文对象里,这样就在webapi项目里读取配置文件信息了。
①删除上面创建的静态类ConfigurationHelper,并且在webapi的Startup类的构造函数也不需要进行注入了,删除即可。
②回到类库,在创建好的上下文对象里删除重写的OnConfiguring方法,因为连接字符串等配置信息直接在webapi项目里传一个配置好的上下文对象过来即可。
③修改EfCoreDemoContext上下文类的有参构造函数为:
也就是接收一个自身的配置上下文对象,这样在webapi项目里用构造函数注入过来即可
public EfCoreDemoContext(DbContextOptions<EfCoreDemoContext> options) : base(options){}
④去webapi项目的Startup类的ConfigureServices方法进行依赖注入
这里的上下文对象就是配置好连接字符串的上下文对象,然后类库的上下文对象用构造函数接收即可。
services.AddDbContext<EfCoreDemoContext>(options=> {
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"));
});
⑤可以不在控制器里直接操作EF上下文,一般都是通过三层架构来,比如BLL,或者DAL
这里我们创建一个BLL类库,用来操作EF,在里面创建一个GetUser类
namespace BLL
{
public class GetUser
{
private EfCoreDemoContext _efCoreDemoContext;
public GetUser(EfCoreDemoContext efCoreDemoContext)
{
_efCoreDemoContext = efCoreDemoContext;
}
public string GetName()
{
var user = _efCoreDemoContext.Users.FirstOrDefault(m => m.Email == "123");
return user.Email;
}
}
}
⑥webapi里还是要注入,否则类库里也得不到上下文对象
services.AddDbContext<EfCoreDemoContext>(options=> {
options.UseSqlServer(Configuration.GetConnectionString("SchoolContext"));
});
⑦控制器里用这个类库的GetUser类即可。
注意,要通过依赖注入的方式注入GetUser类,否则构造函数里直接实例化是不行的,因为没有无参构造函数,就算有也不行,因为不通过依赖注入GetUser类,它里面的_efCoreDemoContext字段是没有值的。要通过容器给它里面的字段赋值。所以要通过构造函数注入来得到GetUser的对象。
namespace WebApiDemo.Controllers
{
[Route("/[controller]")]
[ApiController]
public class HomeController : ControllerBase
{
private GetUser _useEF;
public HomeController(GetUser useEF)
{
_useEF = useEF;
}
[HttpGet]
public string GetUser()
{
return _useEF.GetName();
}
}
}
⑧依赖注入这个GetUser类的实例
services.AddScoped<GetUser>();
然后运行webapi的控制器即可。
如果第一次创建数据库时不用数据库迁移命令创建。可以直接运行api项目创建。步骤如下:
这样做可以第一次也不用将数据库连接字符串写死在上下文对象的OnConfiguring方法里。
在api项目里创建一个类
public static class DbInitializer
{
public static void Initialize(SchoolContext context)
{
var isscuess = context.Database.EnsureCreated();
}
}
修改api项目的program类(修改 Main 方法调用初始化数据库)
public class Program
{
public static void Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
private static void CreateDbIfNotExists(IHost host)
{
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var context = services.GetRequiredService<EfCoreContext>();
DbInitializer.Initialize(context);
}
}
}
运行即可创建数据库。