.NET之生成数据库全流程
开篇语
本文主要是回顾下从项目创建到生成数据到数据库(代码优先)的全部过程。采用EFCore作为ORM框架。
本次示例环境:vs2019、net5、mysql
创建项目
本次事例代码是用过vs2019创建的ASP.NET Core Web API项目
可以通过可视化界面创建或者通过命令行创建
dotnet new webapi -o Net5ByDocker
创建实体类
安装组件
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="5.0.0" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Json.Newtonsoft" Version="5.0.0" />
增加实体类
[Table("user")]
public class User
{
public User()
{
Id = Guid.NewGuid().ToString();
}
public User(string account, string password, string creater) : this()
{
Account = account;
Password = password;
Deleted = false;
SetCreater(creater);
}
[Key]
[Comment("主键")]
[StringLength(36)]
[Required]
public string Id { get; private set; }
[Comment("帐号")]
[StringLength(36)]
[Required]
public string Account { get; private set; }
[Comment("密码")]
[StringLength(36)]
[Required]
public string Password { get; private set; }
[Comment("余额")]
[Column(TypeName = "decimal(18, 2)")]
[Required]
public decimal Money { get; set; }
[Comment("是否删除")]
[Column(TypeName = "tinyint(1)")]
[Required]
public bool Deleted { get; private set; }
[Comment("创建人")]
[StringLength(20)]
[Required]
public string Creater { get; private set; }
[Comment("创建时间")]
[Required]
public DateTime CreateTime { get; private set; }
[Comment("修改人")]
[StringLength(20)]
[Required]
public string Modifyer { get; private set; }
[Comment("修改时间")]
[Required]
public DateTime ModifyTime { get; private set; }
public void SetCreater(string name)
{
Creater = name;
CreateTime = DateTime.Now;
SetModifyer(name);
}
public void SetModifyer(string name)
{
Modifyer = name;
ModifyTime = DateTime.Now;
}
}
这种只是增加实体类类型的一种方式,可能这种看着比较乱,还可以通过OnModelCreating实现,详情看参考文档
增加数据库上下文OpenDbContext
public class OpenDbContext : DbContext
{
public OpenDbContext(DbContextOptions<OpenDbContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
}
Startup注入连接数据库操作
var connection = Configuration["DbConfig:Mysql:ConnectionString"];
var migrationsAssembly = IntrospectionExtensions.GetTypeInfo(typeof(Startup)).Assembly.GetName().Name;
services.AddDbContext<OpenDbContext>(option => option.UseMySql(connection, ServerVersion.AutoDetect(connection), x =>
{
x.UseNewtonsoftJson();
x.MigrationsAssembly(migrationsAssembly);
}));
生成迁移文件
引用组件
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.5">
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.5">
迁移命令
add-migration Init
结果

要看下生成的迁移文件是否是自己预期的那样子,也可以在这一步就生成数据库,命令:Update-Database
数据种子
增加OpenDbSend类,添加数据种子
public class OpenDbSend
{
/// <summary>
/// 生成数据库以及数据种子
/// </summary>
/// <param name="dbContext">数据库上下文</param>
/// <param name="loggerFactory">日志</param>
/// <param name="retry">重试次数</param>
/// <returns></returns>
public static async Task SeedAsync(OpenDbContext dbContext,
ILoggerFactory loggerFactory,
int? retry = 0)
{
int retryForAvailability = retry.Value;
try
{
dbContext.Database.Migrate();//如果当前数据库不存在按照当前 model 创建,如果存在则将数据库调整到和当前 model 匹配
await InitializeAsync(dbContext).ConfigureAwait(false);
//if (dbContext.Database.EnsureCreated())//如果当前数据库不存在按照当前 model创建,如果存在则不管了。
// await InitializeAsync(dbContext).ConfigureAwait(false);
}
catch (Exception ex)
{
if (retryForAvailability < 3)
{
retryForAvailability++;
var log = loggerFactory.CreateLogger<OpenDbSend>();
log.LogError(ex.Message);
await SeedAsync(dbContext, loggerFactory, retryForAvailability).ConfigureAwait(false);
}
}
}
/// <summary>
/// 初始化数据
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public static async Task InitializeAsync(OpenDbContext context)
{
if (!context.Set<User>().Any())
{
await context.Set<User>().AddAsync(new User("azrng", "123456", "azrng")).ConfigureAwait(false);
await context.Set<User>().AddAsync(new User("张三", "123456", "azrng")).ConfigureAwait(false);
}
await context.SaveChangesAsync().ConfigureAwait(false);
}
}
设置项目启动时候调用
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var services = scope.ServiceProvider;
var loggerFactory = services.GetRequiredService<ILoggerFactory>();
var _logger = loggerFactory.CreateLogger<Program>();
try
{
var openContext = services.GetRequiredService<OpenDbContext>();
await OpenDbSend.SeedAsync(openContext, loggerFactory).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError(ex, $"项目启动出错 {ex.Message}");
}
}
await host.RunAsync().ConfigureAwait(false);
}
生成数据库
启动项目,自动生成数据库

表结构如下

如果后期数据库字段或者结构有变动,可以再次生成迁移文件然后生成数据库
查询数据
/// <summary>
/// 用户接口
/// </summary>
public interface IUserService
{
string GetName();
/// <summary>
/// 查询用户信息
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
Task<User> GetDetailsAsync(string account);
}
/// <summary>
/// 用户实现
/// </summary>
public class UserService : IUserService
{
private readonly OpenDbContext _dbContext;
public UserService(OpenDbContext dbContext)
{
_dbContext = dbContext;
}
public string GetName()
{
return "AZRNG";
}
///<inheritdoc cref="IUserService.GetDetailsAsync(string)"/>
public async Task<User> GetDetailsAsync(string account)
{
return await _dbContext.Set<User>().FirstOrDefaultAsync(t => t.Account == account).ConfigureAwait(false);
}
}
一般更推荐建立指定的返回Model类,然后只查询需要的内容,不直接返回实体类
控制器方法
/// <summary>
/// 查询用户详情
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult<User>> GetDetailsAsync(string account)
{
return await _userService.GetDetailsAsync(account).ConfigureAwait(false);
}
查询结果
{
"id": "e8976d0a-6ee9-4e2e-b8d8-1fe6e85b727b",
"account": "azrng",
"password": "123456",
"money": 0,
"deleted": false,
"creater": "azrng",
"createTime": "2021-05-09T15:48:45.730302",
"modifyer": "azrng",
"modifyTime": "2021-05-09T15:48:45.730425"
}
参考文档
实体类型:https://docs.microsoft.com/zh-cn/ef/core/modeling/entity-types?tabs=data-annotations
实体属性:https://docs.microsoft.com/zh-cn/ef/core/modeling/entity-properties?tabs=data-annotations%2Cwithout-nrt
微信公众号

.NET之生成数据库全流程的更多相关文章
- EF使用CodeFirst方式生成数据库&技巧经验
前言 EF已经发布很久了,也有越来越多的人在使用EF.如果你已经能够非常熟练的使用EF的功能,那么就不需要看了.本文意在将自己使用EF的方式记录下来备忘,也是为了给刚刚入门的同学一些指导.看完此文,你 ...
- 生成 PDF 全攻略【2】在已有PDF上添加内容
项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...
- springboot 事务执行全流程分析
springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...
- 【拖拽可视化大屏】全流程讲解用python的pyecharts库实现拖拽可视化大屏的背后原理,简单粗暴!
"整篇文章较长,干货很多!建议收藏后,分章节阅读." 一.设计方案 整体设计方案思维导图: 整篇文章,也将按照这个结构来讲解. 若有重点关注部分,可点击章节目录直接跳转! 二.项目 ...
- MVC Code First 自动生成数据库
1.新建一个MVC项目
- Visor 应用之一 通过ER 设计生成数据库脚本和实体对象
前言 Visor(http://www.visor.com.cn) 是一个基于HTML5 Canvas 开发的IDE 框架和设计开发平台,有关Visor的设计架构和技术应用,在以后的文章里会逐渐跟 ...
- 全球首个全流程跨平台界面开发套件,PowerUI分析
一. 首个全流程跨平台界面开发套件,PowerUI正式发布 UIPower在DirectUI的基础上,自主研发全球首个全流程跨平台界面开发套件PowerUI(PUI)正式发布,PowerU ...
- Entity Framework - Func引起的数据库全表查询
原文:http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html 使用 Entity Framework 最要 ...
- CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-总目录
CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-总目录: 0.Windows 10本机下载Xshell,以方便往Linux主机上上传大文件 1.CentOS7+CDH5.14.0安 ...
随机推荐
- C# 8 中的异步迭代器 IAsyncEnumerable<T> 解析
异步编程已经流行很多年了,.NET 引入的 async 和 await 关键词让异步编程更具有可读性,但有一个遗憾,在 C# 8 之前都不能使用异步的方式处理数据流,直到 C# 8 引入的 IAsyn ...
- P1208 [USACO1.3]混合牛奶 Mixing Milk(JAVA语言)
思路 按单价排序然后贪心 题目描述 由于乳制品产业利润很低,所以降低原材料(牛奶)价格就变得十分重要.帮助Marry乳业找到最优的牛奶采购方案. Marry乳业从一些奶农手中采购牛奶,并且每一位奶农为 ...
- 关于Handler同步屏障你可能不知道的问题
前言 很高兴遇见你 ~ 关于handler的内容,基本每个android开发者都掌握了,网络中的优秀博客也非常多,我之前也写过一篇文章,读者感兴趣可以去看看:传送门. 这篇文章主要讲Handler中的 ...
- 图解双链表(Java实现)
原创公众号:bigsai 文章已收录在 全网都在关注的数据结构与算法学习仓库 前言 前面有很详细的讲过线性表(顺序表和链表),当时讲的链表以但链表为主,但实际上在实际应用中双链表的应用多一些就比如Li ...
- python基础之赋值运算
之前的文章说明了变量的三大组成部分,详细说明了变量名与变量值,但是对于赋值这一块介绍相对较少,今天就来对这一部分进行补充,除了egon老湿所讲之外,本喵还参阅了<python3-cookbook ...
- [树形DP]战略游戏
战 略 游 戏 战略游戏 战略游戏 题目描述 Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题.他要建立一个古城堡,城堡中的路形成一棵树.他要在这棵树的结点上 ...
- [Fundamental of Power Electronics]-PART I-5.不连续导电模式-5.1 DCM来源和模式边界
引子: 当使用电流单向和/或电压单向半导体开关实现DC-DC变换器的理想开关时,可能会出现一种或多种被称为不连续导电模式(DCM)的新工作模式.当电感电流或电容电压的纹波大到足以导致所施加的开关电流或 ...
- HCL实验8:NAT搭建私有网络
NAT 通过NAT技术,进行私有网络的搭建 拓扑图 先对路由器的端口进行配置 R1 [H3C]sys R1 [R1]INT G0/0 [R1-GigabitEthernet0/0]ip address ...
- 源码篇:Handler那些事
前言 Handler属于八股文中非常经典的一个考题了,导致这个知识点很多时候,考官都懒得问了:这玩意很久之前就看过,但是过了一段时间,就很容易忘记,但是处理内存泄漏,aidlHandler之类的考点答 ...
- JS基础学习第二天
类型转换 类型转换就是指将其他的数据类型,转换为String Number 或 Boolean 转换为String 方式一(强制类型转换): 调用被转换数据的toString()方法例子:var a ...