开篇语

本文主要是回顾下从项目创建到生成数据到数据库(代码优先)的全部过程。采用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

结果


image.png

要看下生成的迁移文件是否是自己预期的那样子,也可以在这一步就生成数据库,命令: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);
        }

生成数据库

启动项目,自动生成数据库


image.png

表结构如下


image.png

如果后期数据库字段或者结构有变动,可以再次生成迁移文件然后生成数据库

查询数据

    /// <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之生成数据库全流程的更多相关文章

  1. EF使用CodeFirst方式生成数据库&技巧经验

    前言 EF已经发布很久了,也有越来越多的人在使用EF.如果你已经能够非常熟练的使用EF的功能,那么就不需要看了.本文意在将自己使用EF的方式记录下来备忘,也是为了给刚刚入门的同学一些指导.看完此文,你 ...

  2. 生成 PDF 全攻略【2】在已有PDF上添加内容

    项目在变,需求在变,不变的永远是敲击键盘的程序员..... PDF 生成后,有时候需要在PDF上面添加一些其他的内容,比如文字,图片.... 经历几次失败的尝试,终于获取到了正确的代码书写方式. 在此 ...

  3. springboot 事务执行全流程分析

    springboot 事务执行全流程分析 目录 springboot 事务执行全流程分析 1. 事务方法执行前的准备工作 2. 业务代码的调用 3. 事务方法执行后处理 4. 业务代码在事务和非事务中 ...

  4. 【拖拽可视化大屏】全流程讲解用python的pyecharts库实现拖拽可视化大屏的背后原理,简单粗暴!

    "整篇文章较长,干货很多!建议收藏后,分章节阅读." 一.设计方案 整体设计方案思维导图: 整篇文章,也将按照这个结构来讲解. 若有重点关注部分,可点击章节目录直接跳转! 二.项目 ...

  5. MVC Code First 自动生成数据库

    1.新建一个MVC项目

  6. Visor 应用之一 通过ER 设计生成数据库脚本和实体对象

    前言 Visor(http://www.visor.com.cn)   是一个基于HTML5 Canvas 开发的IDE 框架和设计开发平台,有关Visor的设计架构和技术应用,在以后的文章里会逐渐跟 ...

  7. 全球首个全流程跨平台界面开发套件,PowerUI分析

    一.       首个全流程跨平台界面开发套件,PowerUI正式发布 UIPower在DirectUI的基础上,自主研发全球首个全流程跨平台界面开发套件PowerUI(PUI)正式发布,PowerU ...

  8. Entity Framework - Func引起的数据库全表查询

    原文:http://www.cnblogs.com/dudu/archive/2012/04/01/enitity_framework_func.html 使用 Entity Framework 最要 ...

  9. CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-总目录

    CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-总目录: 0.Windows 10本机下载Xshell,以方便往Linux主机上上传大文件 1.CentOS7+CDH5.14.0安 ...

随机推荐

  1. PTE 准备之 Read aloud

    Read aloud A text appears on screen.Read the text aloud rext up tp 60 words varies by task, dependin ...

  2. java中常见的内存泄露的例子

    JAVA 中的内存泄露     Java中的内存泄露,广义并通俗的说,就是:不再会被使用的对象的内存不能被回收,就是内存泄露.     Java中的内存泄露与C++中的表现有所不同.     在C++ ...

  3. 2019HDU多校第一场 6582 Path 【最短路+最大流最小割】

    一.题目 Path 二.分析 首先肯定要求最短路,然后如何确定所有的最短路其实有多种方法. 1 根据最短路,那么最短路上的边肯定是可以满足$dist[from] + e.cost = dist[to] ...

  4. golang 实现求两向量夹角

    type Vector3 struct { X float64 `json:"x"` Y float64 `json:"y"` Z float64 `json: ...

  5. 【python+selenium的web自动化】- 针对上传操作的实现方案

    如果想从头学起selenium,可以去看看这个系列的文章哦! https://www.cnblogs.com/miki-peng/category/1942527.html 关于上传操作 ​ 上传有两 ...

  6. java常用算法笔记

    1.将一个10进制的c转换为n进制 String s=new BigInteger(c+"",10).toString(n); 2. 求一个解退出 System.exit(0): ...

  7. Android Studio详解项目中的资源

    •目录结构 •作用 所有以 drawable 开头的文件都是用来放图片的: 所有以 mipmap 开头的文件都是用来放应用图标的: 所有以 value 开头的文件夹都是用来放字符串.样式.颜色等配置的 ...

  8. [Fundamental of Power Electronics]-PART II-8. 变换器传递函数-8.4 变换器传递函数的图形化构建

    8.4 变换器传递函数的图形化构建 第7章推导出的buck变换器小信号等效电路模型在图8.55中再次给出.让我们用上一节的图解方法来构造该变换器的传递函数和端阻抗. Fig. 8.55 Small-s ...

  9. 自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构

    自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构 欢迎加QQ群:1026880196 进行交流学习 环境说明: 1. 满足一台电脑一个网卡的环境 ...

  10. 网络编程NIO之Reactor线程模型

    目录 单Reactor线程模型 基于工作线程的Reactor线程模型 多Reactor线程模型 多Reactor线程模型示例 结束语 上篇文章中写了一些NIO相关的知识以及简单的NIO实现示例,但是示 ...