专栏首页Ken的杂谈ASP.NET Core 入门教程 8、ASP.NET Core + Entity Framework Core 数据访问入门
原创

ASP.NET Core 入门教程 8、ASP.NET Core + Entity Framework Core 数据访问入门

一、前言

1、本教程主要内容

  • ASP.NET Core MVC 集成 EF Core 介绍&操作步骤
  • ASP.NET Core MVC 使用 EF Core + Linq to Entity 访问MySQL数据库
  • ASP.NET Core MVC 使用 EF Core + 原生SQL访问MySql数据库
  • EF Core + MySQL数据库插入数据后获取自增列的值

Entity Framework Core 简称为 EF Core

2、本教程环境信息

软件/环境

说明

操作系统

Windows 10

SDK

2.1.401

ASP.NET Core

2.1.3

MySQL

8.0.x

IDE

Visual Studio Code 1.30

浏览器

Chrome 70

VS Code插件

版本

说明

C#

1.17.1

提供C#智能感知, .NET Core 调试、编译等

vscdoe-solution-explorer

0.3.1

提供解决方案视图

本篇代码以下代码进行调整:https://github.com/ken-io/asp.net-core-tutorial/tree/master/chapter-02

3、准备工作

安装MySQL数据库:https://dev.mysql.com/downloads/mysql/

  • Windows环境

下载安装包后双击安装,一直下一步即可。

  • MacOS环境

参考:https://ken.io/note/macos-mysql8-install-config-tutorial

  • CentOS环境

参考:https://ken.io/note/centos-mysql8-setup

4、前置知识

  • 控制反转(IOC)原则与依赖注入(DI)

ASP.NET Core 默认集成了DI。所有官方模块的引入都要使用DI的方式引入。

https://baike.baidu.com/item/IOC

  • Linq使用教程

https://docs.microsoft.com/zh-cn/dotnet/csharp/tutorials/working-with-linq

二、EF Core + MySQL 前置准备

EF Core 全称:Entity Framework Core,为微软为 .NET Core平台开发的ORM框架。对应是 .NET Framework平台的 Entity Framework(EF),无论是EF还是EF Core都可以说是 .NET 平台开发效率最高的ORM框架。

1、引入 EF Core + MySQL Provider

EF Core已经集成在 ASP.NET Core 中,但默认并不支持MySQL,如果需要连接MySQL,需要添加MySQL相关的Provider,这里我选择的是:Pomelo.EntityFrameworkCore.MySql

任意命令行操作即可,我用的是VS Code自带的命令行

//进入项目根目录: Ken.Tutorial.Web
cd Ken.Tutorial.Web

//添加Package
dotnet add package Pomelo.EntityFrameworkCore.MySql

这里我添加的 MySql.Data.EntityFrameworkCore 版本是 8.0.13,如果你想跟我使用一样的版本,可以使用以下命令:

dotnet add package Pomelo.EntityFrameworkCore.MySql --version 2.1.4

2、创建MySQL库表

  • 创建数据库
CREATE DATABASE ken_tutorial;
  • 创建表
USE ken_tutorial;

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `hobby` varchar(500) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

3、配置链接字符串

在项目根目录Ken.Tutorial.Web中创建配置文件appsettings.json,并写入以下配置

{
  "ConnectionStrings": {
    "testdb": "server=localhost;database=Ken.Tutorial;uid=root;pwd=root;"
  }
}

4、实体&DbContext准备

创建user表对应实体

在项目根目录Ken.Tutorial.Web中创建目录Models,并在其中创建类:UserEntity.cs

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Ken.Tutorial.Web.Models
{
    [Table("user")]
    [Serializable]
    public class UserEntity
    {
        [Key]//主键
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]//自增列
        [Column("id")]
        public int Id { get; set; }

        [Column("name")]
        public string Name { get; set; }

        [Column("age")]
        public int Age { get; set; }

        [Column("hobby")]
        public string Hobby { get; set; }
    }
}

创建DBContext

在项目根目录Ken.Tutorial.Web中创建目录Repositories,并在其中创建类:TutorialDbContext.cs

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace Ken.Tutorial.Web.Repositories
{
    public class TutorialDbContext : DbContext
    {
        private IConfiguration Configuration { get; }

        public TutorialDbContext(IConfiguration configuration)
        {
            this.Configuration = configuration;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseMySql(Configuration.GetConnectionString("testdb"));
        }

        ppublic DbSet<UserEntity> Users { get; set; }
    }
}

TutorialDbContext 继承了 DbContext,然后再Context初始化时配置MySQL链接。

由于 ASP.NET Core 默认使用了DI组件,所以我们取配置文件,就需要在构造函数中获取 IConfiguration 注入的实例。

在Startup.cs配置注入,以便数据访问类可以访问DI方式获取TutorialDbContext

public void ConfigureServices(IServiceCollection services)
{
    //引入MVC模块
    services.AddMvc();

    //配置DbContext注入
    services.AddTransient<TutorialDbContext>();
}

三、EF Core + Linq to entity 访问数据库

1、创建Linq To Entity 数据访问类

using System;
using System.Collections.Generic;
using System.Linq;
using Ken.Tutorial.Web.Models;

namespace Ken.Tutorial.Web.Repositories
{
    public class TutorialRepository
    {
        private TutorialDbContext DbContext { get; }

        public TutorialRepository(TutorialDbContext dbContext)
        {
            //在构造函数中注入DbContext
            this.DbContext = dbContext;
        }

        //添加
        public int Add(UserEntity user)
        {
            using (DbContext)
            {
                //由于我们在UserEntity.Id配置了自增列的Attribute,EF执行完成后会自动把自增列的值赋值给user.Id
                DbContext.Users.Add(user);
                return DbContext.SaveChanges();
            }

        }

        //删除
        public int Delete(int id)
        {
            using (DbContext)
            {
                var userFromContext = DbContext.Users.FirstOrDefault(u => u.Id == id);
                DbContext.Users.Remove(userFromContext);
                return DbContext.SaveChanges();
            }
        }

        //更新
        public int Update(UserEntity user)
        {
            using (DbContext)
            {
                var userFromContext = DbContext.Users.FirstOrDefault(u => u.Id == user.Id);
                userFromContext.Name = user.Name;
                userFromContext.Age = user.Age;
                userFromContext.Hobby = user.Hobby;
                return DbContext.SaveChanges();
            }
        }

        //查询
        public UserEntity QueryById(int id)
        {
            using (DbContext)
            {
                return DbContext.Users.FirstOrDefault(u => u.Id == id);
            }
        }

        //查询集合
        public List<UserEntity> QueryByAge(int age)
        {
            using (DbContext)
            {
                return DbContext.Users.Where(u => u.Age == age).ToList();
            }
        }

        //查看指定列
        public List<string> QueryNameByAge(int age)
        {
            using (DbContext)
            {
                return DbContext.Users.Where(u => u.Age == age).Select(u => u.Name).ToList();
            }
        }

        //分页查询
        public List<UserEntity> QueryUserPaging(int pageSize, int page)
        {
            using (DbContext)
            {
                return DbContext.Users.Skip(pageSize * (page - 1)).Take(pageSize).ToList();
            }
        }

        //事务:将年龄<0的用户修改年龄为0
        public int FixAge()
        {
            using (DbContext)
            {
                using (var transaction = DbContext.Database.BeginTransaction())
                {
                    try
                    {
                        var userListFromContext = DbContext.Users.Where(u => u.Age < 0);
                        foreach (UserEntity u in userListFromContext)
                        {
                            u.Age = 0;
                        }
                        var count = DbContext.SaveChanges();
                        transaction.Commit();
                        return count;
                    }
                    catch
                    {
                        transaction.Rollback();
                        return 0;
                    }
                }
            }
        }
    }
}

2、创建测试API

Controllers文件夹下创建EfCoreController.cs作为访问入口

using System;
using Ken.Tutorial.Web.Models;
using Ken.Tutorial.Web.Repositories;
using Microsoft.AspNetCore.Mvc;

namespace Ken.Tutorial.Web.Controllers
{
    public class EfCoreController : Controller
    {
        public TutorialRepository Repository { get; }

        public EfCoreController(TutorialRepository repository)
        {
            this.Repository = repository;
        }

        public IActionResult Add(UserEntity user)
        {
            var message = Repository.Add(user) > 0 ? "success" : "failed";
            return Json(new { Message = message, User = user });
        }

        public IActionResult Delete(int id)
        {
            var message = Repository.Delete(id) > 0 ? "success" : "failed";
            return Json(new { Message = message });
        }

        public IActionResult Update(UserEntity user)
        {
            var message = Repository.Update(user) > 0 ? "success" : "failed";
            return Json(new { Message = message, User = user });
        }

        public IActionResult QueryById(int id)
        {
            var user = Repository.QueryById(id);
            return Json(new { User = user });
        }

        public IActionResult QueryByAge(int age)
        {
            var users = Repository.QueryByAge(age);
            return Json(new { Users = users });
        }

        public IActionResult QueryNameByAge(int age)
        {
            var users = Repository.QueryNameByAge(age);
            return Json(new { Users = users });
        }

        public IActionResult QueryUserPaging(int pageSize, int page)
        {
            var users = Repository.QueryUserPaging(pageSize, page);
            return Json(new { Users = users });
        }

        public IActionResult FixAge()
        {
            var count = Repository.FixAge();
            return Json(new { FixCount = count });
        }

    }
}

3、启动测试

  • 在Startup.cs中配置Repository注入
public void ConfigureServices(IServiceCollection services)
{
    //其他代码省略

    //配置Repository注入
    services.AddTransient<TutorialRepository>();
}
  • 启动项目并测试

API

示例

添加用户

/efcore/add?name=ken&age=18&hobby=coding

删除用户

/efcore/delete?id=0

更新用户

/efcore/update?id=1&name=ken&age=666&hobby=codingOrGaming

查询单个用户

/efcore/querybyid?id=0

查询多个用户

/efcore/querybyage?age=18

查询多个用户名

/efcore/querynamebyage?age=18

分页查询用户

/efcore/queryuserpaging?pagesize=3&page=1

修复异常年龄

/efcore/fixage

四、EF Core + 原生SQL 访问数据库

1、创建EF Core + 原生SQL 数据访问类

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using Ken.Tutorial.Web.Models;
using Microsoft.EntityFrameworkCore;
using MySql.Data.MySqlClient;

namespace Ken.Tutorial.Web.Repositories
{
    public class TutorialWithSqlRepository
    {
        private TutorialDbContext DbContext { get; }

        public TutorialWithSqlRepository(TutorialDbContext dbContext)
        {
            //在构造函数中注入DbContext
            this.DbContext = dbContext;
        }

        //添加
        public int Add(UserEntity user)
        {
            using (var connection = DbContext.Database.GetDbConnection())
            {
                connection.Open();
                var command = connection.CreateCommand() as MySqlCommand;
                command.CommandText = "INSERT INTO user (name,age,hobby) VALUES(@name,@age,@hobby)";
                command.Parameters.Add(new MySqlParameter()
                {
                    ParameterName = "@name",
                    DbType = DbType.String,
                    Value = user.Name
                });
                command.Parameters.Add(new MySqlParameter()
                {
                    ParameterName = "@age",
                    DbType = DbType.Int32,
                    Value = user.Age
                });
                command.Parameters.Add(new MySqlParameter()
                {
                    ParameterName = "@hobby",
                    DbType = DbType.String,
                    Value = user.Hobby
                });
                var count = command.ExecuteNonQuery();
                //获取插入时产生的自增列Id并赋值给user.Id使用
                user.Id = (int)command.LastInsertedId;
                return count;
            }

        }

        //删除
        public int Delete(int id)
        {
            using (DbContext)
            {
                return DbContext.Database.ExecuteSqlCommand(
                    "DELETE FROM user WHERE id={0}", id);
            }
        }

        //更新
        public int Update(UserEntity user)
        {
            using (DbContext)
            {
                return DbContext.Database.ExecuteSqlCommand(
                     "UPDATE user SET name={0}, age={1}, hobby={2} WHERE id={3}",
                      user.Name, user.Age, user.Hobby, user.Id);
            }
        }

        //查询
        public UserEntity QueryById(int id)
        {
            using (DbContext)
            {
                return DbContext.Users.FromSql("SELECT id,name,age,hobby FROM user WHERE id={0}", id).FirstOrDefault();
            }
        }

        //查询集合
        public List<UserEntity> QueryByAge(int age)
        {
            using (DbContext)
            {
                return DbContext.Users.FromSql("SELECT id,name,age,hobby FROM user WHERE age={0}", age).ToList();
            }
        }

        //查看指定列
        public List<string> QueryNameByAge(int age)
        {
            using (DbContext)
            {
                return DbContext.Users.FromSql("SELECT id,name FROM user WHERE age={0}", age).Select(u => u.Name).ToList();
            }
        }

        //分页查询
        public List<UserEntity> QueryUserPaging(int pageSize, int page)
        {
            using (DbContext)
            {
                return DbContext.Users.FromSql("SELECT id,name,age,hobby FROM user LIMIT {0},{1}", pageSize * (page - 1), pageSize).ToList();
            }
        }

        //事务:将年龄<0的用户修改年龄为0
        public int FixAge()
        {
            using (DbContext)
            {
                using (var connection = DbContext.Database.GetDbConnection())
                {
                    //打开连接
                    connection.Open();
                    //开启事务
                    using (var transaction = connection.BeginTransaction())
                    {
                        try
                        {
                            //获取命令对象
                            var command = connection.CreateCommand();
                            command.Transaction = transaction;
                            command.CommandText = "UPDATE user SET age=@age WHERE age<@age";
                            command.Parameters.Add(new MySqlParameter()
                            {
                                ParameterName = "@age",
                                DbType = DbType.Int32,
                                Value = 0
                            });
                            var count = command.ExecuteNonQuery();
                            transaction.Commit();
                            return count;
                        }
                        catch (Exception ex)
                        {
                            connection.Close();
                            transaction.Rollback();
                            return 0;
                        }
                    }

                }
            }
        }
    }
}

2、创建测试API

Controllers文件夹下创建EfCoreWithSqlController.cs作为访问入口

using System;
using Ken.Tutorial.Web.Models;
using Ken.Tutorial.Web.Repositories;
using Microsoft.AspNetCore.Mvc;

namespace Ken.Tutorial.Web.Controllers
{
    public class EfCoreWithSqlController : Controller
    {
        public TutorialWithSqlRepository Repository { get; }

        public EfCoreWithSqlController(TutorialWithSqlRepository repository)
        {
            this.Repository = repository;
        }

        public IActionResult Add(UserEntity user)
        {
            var message = Repository.Add(user) > 0 ? "success" : "failed";
            return Json(new { Message = message, User = user });
        }

        public IActionResult Delete(int id)
        {
            var message = Repository.Delete(id) > 0 ? "success" : "failed";
            return Json(new { Message = message });
        }

        public IActionResult Update(UserEntity user)
        {
            var message = Repository.Update(user) > 0 ? "success" : "failed";
            return Json(new { Message = message, User = user });
        }

        public IActionResult QueryById(int id)
        {
            var user = Repository.QueryById(id);
            return Json(new { User = user });
        }

        public IActionResult QueryByAge(int age)
        {
            var users = Repository.QueryByAge(age);
            return Json(new { Users = users });
        }

        public IActionResult QueryNameByAge(int age)
        {
            var users = Repository.QueryNameByAge(age);
            return Json(new { Users = users });
        }

        public IActionResult QueryUserPaging(int pageSize, int page)
        {
            var users = Repository.QueryUserPaging(pageSize, page);
            return Json(new { Users = users });
        }

        public IActionResult FixAge()
        {
            var count = Repository.FixAge();
            return Json(new { FixCount = count });
        }

    }
}

3、启动测试

  • 在Startup.cs中配置Repository注入
public void ConfigureServices(IServiceCollection services)
{
    //其他代码省略

    //配置Repository注入
    services.AddTransient<TutorialWithSqlRepository>();
}
  • 启动项目并测试

API

示例

添加用户

/efcorewithsql/add?name=ken&age=18&hobby=coding

删除用户

/efcorewithsql/delete?id=0

更新用户

/efcorewithsql/update?id=1&name=ken&age=666&hobby=codingOrGaming

查询单个用户

/efcorewithsql/querybyid?id=0

查询多个用户

/efcorewithsql/querybyage?age=18

查询多个用户名

/efcorewithsql/querynamebyage?age=18

分页查询用户

/efcorewithsql/queryuserpaging?pagesize=3&page=1

修复异常年龄

/efcorewithsql/fixage

五、备注

1、附录

  • 本文代码示例

https://github.com/ken-io/asp.net-core-tutorial/tree/master/chapter-08

  • 本文参考

https://docs.microsoft.com/zh-cn/ef/core https://www.learnentityframeworkcore.com https://mysql-net.github.io/MySqlConnector/tutorials/net-core-mvc/


本文首发于我的独立博客:https://ken.io/note/asp.net-core-tutorial-entity-framework-core-mysql

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CentOS 7 下安装.NET Core SDK 2.1

    在Binaries这一栏选择x64版本即可(需要点击链接才回获取到实际下载地址)

    KenTalk
  • JS/Jquery解决回车键触发表单提交问题

    因为现在大多数浏览器,当表单中的文本框或其他可提交元素为当前焦点时,敲回车键就会触发表单提交。

    KenTalk
  • Spring Boot入门教程2-4、使用Spring Boot+MyBatis多数据源配置(xml配置版)

    本项目构建基于:https://ken.io/note/springboot-course-basic-curd-xml

    KenTalk
  • 企业大数据价值你只发掘了1%!

    管理学上对企业定义为“以赢利为目的的组织”—这句话会在本书中多次重复以示强调—意思是通过充分利用公司的内外部资源,将资源转换,实现增值,从而赢利。就像一个黑匣子...

    明悦数据
  • 玩转机器学习:基于多损失函数的模型融合

    原理其实很简单,利用不同损失函数的特性,结合使用不同损失函数分别训练多个模型,将多个训练得到的模型结果进行加权平均或分段预测。这里我们使用的是MAE 和 MSE...

    统计学家
  • jQuery解析ajax 返回的json

    week
  • 重写ThreadPoolTaskExecutor

    参考代码:https://github.com/Noneplus/ConcurrentDemo

    Noneplus
  • 通过transmittable-thread-local源码理解线程池线程本地变量传递的原理

    最近一两个月花了很大的功夫做UCloud服务和中间件迁移到阿里云的工作,没什么空闲时间撸文。想起很早之前写过ThreadLocal的源码分析相关文章,里面提到了...

    Throwable
  • 助力学前教育信息化建设 腾讯联手深圳龙华区打造智慧幼儿园

    ? 12月21日,腾讯教育云“学前教育信息化研讨会(龙华专场)”在深圳腾讯总部滨海大厦召开,深圳市龙华区教科院信息科技部主任陈庆涛、深圳市教育科学研究院学前教...

    腾讯智慧教育
  • Facebook不让美国,英国和澳大利亚"走后门"

    Facebook在周一拒绝了美国,英国和澳大利亚的要求。要求提出需要一个“后门”功能来通向端到端加密的Messenger应用,以协助执法机构打击犯罪和恐怖主义。

    shellmik

扫码关注云+社区

领取腾讯云代金券