1. 连接数据库

通过依赖注入配置应用程序,通过startup类的ConfigureService方法中的AddDbContext将EFCore添加到依赖注入容器

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); services.AddDbContext<OpenDbContext>(
options => options.UseMySql(Configuration["DbConfig:Mysql:ConnectionString"]);
}

将名为 OpenDbContext的 DbContext 子类注册到依赖注入容器的Scope生命周期。上下文配置为使用MySQL数据库提供程序,并从配置中读取数据库连接字符串。

OpenDbContext类必须公开具有 DbContextOptions 参数的公共构造函数。 这是将 AddDbContext 的上下文配置传递到 DbContext 的方式。

    public class OpenDbContext : DbContext
{
public OpenDbContext(DbContextOptions options) : base(options)
{
} public DbSet<User> Users { get; set; }
public DbSet<Score> Scores { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//另一种配置连接数据库的方式
//optionsBuilder.UseMySql("连接数据库", ServerVersion.AutoDetect("连接数据库字符串"));
} protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//属性配置
//modelBuilder.Entity<User>().Property(t => t.Account).IsRequired().HasMaxLength(20).HasComment("帐号");
//种子数据设置
//modelBuilder.Entity<User>().HasData(new User { Account="种子"}); //使用下面的方法进行替换处理上面批量增加etc的操作
modelBuilder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); base.OnModelCreating(modelBuilder);
}
}

然后将OpenDbContext通过构造函数注入的方式注入到应用程序的控制器或者其他服务中使用。

关于连接数据库可以参考另一个文章: .Net之生成数据库全流程

2. 操作数据库

    context.Database.EnsureDeleted();//删除数据库,如果存在,如果没有权限,则引发异常
context.Database.EnsureCreated();//如果数据库不存在,创建数据库并初始化数据库架构,如果存在任何表,则不会初始化架构
context.Database.Migrate();//根据迁移文件,迁移数据库

3. 查询操作

3.1 基础查询

db.Set<UserInfor>().ToList();

//查询表达式
var account = (from u in _context.Users
where u.Id == id
select u.Account
).ToList(); //查询单个
_context.Movie.FirstOrDefaultAsync(m => m.ID == id);
_context.Movie.FindAsync(id);
//查询指定列
_context.Set<User>().AsNoTracking().Where(t=>t.Id=="11").Select(t => new { t.Account, t.PassWord }).FirstOrDefaultAsync(); // 预先加载查询
var blogs = context.Blogs.Include(blog => blog.Posts).ToList();
// 包含多个层级的查询
var blogs = context.Blogs.Include(blog => blog.Posts).ThenInclude(post => post.Author).ToList();

3.2 跟踪和非跟踪查询

跟踪行为决定了EFCore是否将有些实体的信息保存在其更改更跟踪器中。如果已跟踪某个实体,则该实体中检测到的任何更改都会在SaveChanges()时候保存到数据库,

不跟踪没有主键的实体类型。

# 跟踪查询
_context.Set<User>().ToListAsync(); # 非跟踪查询
_context.Set<User>().AsNoTracking().ToListAsync();

默认是跟踪查询

3.3 条件查询

3.3.1 不支持异步方案

            Func<User, bool> express = x => true;
if (!string.IsNullOrWhiteSpace(dto.Data))
{
express = x => x.Mobile == dto.Data;
}
string userid = "";
if (!string.IsNullOrWhiteSpace(userid))
{
express = x => x.UserId == userid;
}
var bbb = _dbContext.Set<User>().Where(express).FirstOrDefault();

3.3.2 支持异步方案

            Expression<Func<User, bool>> express = x => true;
if (!string.IsNullOrWhiteSpace(dto.Data))
{
express = x => x.Mobile == dto.Data;
}
var bbb = await _dbContext.Set<User>().Where(express).ToListAsync();

3.4 原生SQL查询

可使用 FromSqlRaw 扩展方法基于原始 SQL 查询开始 LINQ 查询。 FromSqlRaw 只能在直接位于 DbSet<> 上的查询根上使用。

3.4.1 基本原生SQL查询

var blogs = context.Blogs
.FromSqlRaw("select * from user")
.ToList(); // 执行存储过程
var blogs = context.Blogs
.FromSqlRaw("EXECUTE dbo.GetMostPopularBlogs")
.ToList();

3.4.2 参数化查询

3.4.2.1 SQL注入

首先我们编写一个简单的SQL注入示例,比如就注入我们根据ID查询的语句,输入ID为:ididid' or '1'='1

    var strSql = string.Format("select * from user where Id='{0}'", "ididid' or '1'='1");
var query = await _context.Set<User>().FromSqlRaw(strSql).ToListAsync();
Console.WriteLine(JsonConvert.SerializeObject(query));

生成语句

      select * from user where Id='ididid' or '1'='1'
[{"Account":"张三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"},{"Account":"李四","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.849376","IsValid":false,"Id":"1395392303090110464"},{"Account":"王五","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.849425","IsValid":false,"Id":"1395392303090110467"}]

3.4.2.2 FromSqlRaw参数化

通过参数化查询,防止SQL注入问题

    //sql语句参数化查询,防止SQL注入
var strSql = "select * from user where Id=@id";
var parameter = new MySqlParameter[] {
new MySqlParameter("@id","1395392302788120576"),
};
var query = await _context.Set<User>().FromSqlRaw(strSql, parameter).ToListAsync();

或者

    var strSql = "select * from user where Id={0}";
var query = await _context.Set<User>().FromSqlRaw(strSql, "1395392302788120576").ToListAsync();
Console.WriteLine(JsonConvert.SerializeObject(query)); // 生成SQL
select * from user where Id=@p0
[{"Account":"张三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"}]

通过占位符形式提供额外的参数,看上去类似于String.Format语法,但是提供的值包装在DbParameter中。可以防止SQL注入

3.4.2.3 FromSqlInterpolated参数化

FromSqlInterpolated 类似于 FromSqlRaw,但你可以借助它使用字符串内插语法。 与 FromSqlRaw 一样,FromSqlInterpolated 只能在查询根上使用,并且都可以防止SQL注入。

    var query = await _context.Set<User>().FromSqlInterpolated($"select * from user where Id={"1395392302788120576"}").ToListAsync();
Console.WriteLine(JsonConvert.SerializeObject(query));

生成SQL

      select * from user where Id=@p0
[{"Account":"张三","PassWord":"123456","CreateTime":"2021-05-20T22:53:44.778101","IsValid":false,"Id":"1395392302788120576"}]

3.4.3 限制

  • SQL查询必须返回实体类型的所有属性的数据。
  • 结果集中的列明必须与属性映射到的列名称匹配。
  • SQL查询不能包含关联数据, 但是,在许多情况下你可以在查询后面紧跟着使用 Include 方法以返回关联数据(请参阅包含关联数据)。

参考文档:https://docs.microsoft.com/zh-cn/ef/core/querying/raw-sql

3.5 复杂查询

数据如下:

用户表(user)

用户成绩表(score)

描述:包含三个用户,其中两个用户在成绩表都有语文和数学的数据。

3.5.1 内连接

内连接:分为隐式内连接和显式内连接(写法不同,结果相同)

3.5.1.1 Linq查询表达式

显式内连接:join-in-on拼接
    var list = (from u in _context.Users
join sc in _context.Scores on u.Id equals sc.UserId
where sc.CourseName == "语文"
select new
{
u.Account,
u.PassWord,
sc.CourseName,
sc.Grade
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list));

记得引用:System.Linq 否则提示:未找到源类型“DbSet”的查询模式的实现,未找到join

生成SQL

      SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`
FROM `user` AS `u`
INNER JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId`
WHERE `s`.`CourseName` = '语文'

结果

隐式内连接:多个from并联拼接
    var list = (from u in _context.Users
from sc in _context.Scores
where u.Id == sc.UserId && sc.CourseName == "语文"
select new
{
u.Account,
u.PassWord,
sc.CourseName,
sc.Grade
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list));

生成SQL

      SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`
FROM `user` AS `u`
CROSS JOIN `score` AS `s`
WHERE (`u`.`Id` = `s`.`UserId`) AND (`s`.`CourseName` = '语文')

结果

3.5.1.2 Linq标准查询运算符

    var list = _context.Users.Where(t => t.Account != null)
.Join(_context.Scores.Where(sc => sc.CourseName == "语文"), u => u.Id, sc => sc.UserId, (u, sc) => new
{
u.Account,
u.PassWord,
sc.CourseName,
sc.Grade
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list));

生成SQL

      # 不加查询课程
SELECT `u`.`Account`, `u`.`PassWord`, `s`.`CourseName`, `s`.`Grade`
FROM `user` AS `u`
INNER JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId` # 查询课程
SELECT `u`.`Account`, `u`.`PassWord`, `t`.`CourseName`, `t`.`Grade`
FROM `user` AS `u`
INNER JOIN (
SELECT `s`.`CourseName`, `s`.`Grade`, `s`.`UserId`
FROM `score` AS `s`
WHERE `s`.`CourseName` = '语文'
) AS `t` ON `u`.`Id` = `t`.`UserId`

结果

3.5.2 外连接

外连接join后必须有into,然后可以加上XX.DefaultIfEmpty(),表示对于引用类型将返回null,而对于值类型则返回0。对于结构体类型,则会根据其成员类型将它们相应地初始化为null(引用类型)或0(值类型),

如果仅需要统计右表的个数或者其它属性,可以省略XX.DefaultIfEmpty, 但如果需要点出来右表的字段,则不能省。

3.5.2.1 linq实现

查询所有用户对应的班级,因为用户和成绩一对多,所以会出现多条数据

    var list = (from u in _context.Users
join sc in _context.Scores on u.Id equals sc.UserId
into ulist
from sco in ulist.DefaultIfEmpty()
where u.Account != null //这个条件只是展示如何添加条件
select new
{
UserId = u.Id,
Account = u.Account,
sco.CourseName
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list));

生成SQL

      SELECT `u`.`Id` AS `UserId`, `u`.`Account`, `s`.`CourseName`
FROM `user` AS `u`
LEFT JOIN `score` AS `s` ON `u`.`Id` = `s`.`UserId`

结果

如果要查询成绩,应该这么写,上面那个写法会直接报错, Nullable object must have a value

3.5.3 GroupJoin

GroupJoin操作符常应用于返回“主键对象-外键对象集合”形式的查询,例如“用户信息-此用户下所有科目成绩”

    var list = _context.Users.Where(t => t.Account != null)
.GroupJoin(_context.Scores, u => u.Id, sc => sc.UserId, (u, sc) => new
{
u.Account,
u.PassWord,
Scores = sc
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list));

该代码会提示错误,原因如:https://docs.microsoft.com/zh-cn/ef/core/querying/client-eval

3.5.4 GrouBy

分组操作 根据用户分组,求科目数

    var list = (from sc in _context.Scores
group sc by sc.UserId
into g
select new
{
g.Key,
Count = g.Count()
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list)); var list2 = _context.Scores.GroupBy(sc => sc.UserId).Select(t => new
{
t.Key,
Count = t.Count()
}).ToList();
Console.WriteLine(JsonConvert.SerializeObject(list2));

生成SQL

info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT `s`.`UserId` AS `Key`, COUNT(*) AS `Count`
FROM `score` AS `s`
GROUP BY `s`.`UserId`
[{"Key":"1395392302788120576","Count":2},{"Key":"1395392303090110464","Count":2}]
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT `s`.`UserId` AS `Key`, COUNT(*) AS `Count`
FROM `score` AS `s`
GROUP BY `s`.`UserId`
[{"Key":"1395392302788120576","Count":2},{"Key":"1395392303090110464","Count":2}]

4. 添加

4.1 基础添加

    _context.Movie.Add(movie);
// or
await _context.Movie.AddRangeAsync(movies)
await _context.SaveChangesAsync();

4.2 已经设置自增键的插入

先关闭自增然后插入数据后再开启自增

        db.Database.OpenConnection();
db.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [T_RoleInfor] ON");
var r2 = new T_RoleInfor()
{
id = 123,
roleName = "管理员",
roleDescription = "我是管理员"
};
db.Add(r2);
int count2 = db.SaveChanges();
db.Database.ExecuteSqlCommand("SET ID ENTITY_INSERT [T_RoleInfor] OFF");

4.3 通过SQL添加

    var strSql2 = "INSERT INTO `userinfo`(`Id`, `Account`, `PassWord`) VALUES (@id, @account, @password);";
var parameter2 = new MySqlParameter[] {
new MySqlParameter("@id","22"),
new MySqlParameter("@account","2222"),
new MySqlParameter("@password","22222")
};
var flg = db.Database.ExecuteSqlRaw(strSql2, parameter2);

5. 修改

    var  movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
movie.Name="李思";
await _context.SaveChangesAsync();

6. 删除

    var movie = await _context.Movie.FirstOrDefaultAsync(m => m.ID == id);
_context.Movie.Remove(movie);
await _context.SaveChangesAsync();

7. 参考文档

官方例子:https://docs.microsoft.com/zh-cn/ef/core/dbcontext-configuration/

微信公众号

EFCore之增删改查的更多相关文章

  1. abp(net core)+easyui+efcore仓储系统——展现层实现增删改查之控制器(六)

    abp(net core)+easyui+efcore仓储系统目录 abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一) abp(net core)+easyui+e ...

  2. abp(net core)+easyui+efcore实现仓储管理系统——展现层实现增删改查之列表视图(七)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  3. abp(net core)+easyui+efcore实现仓储管理系统——ABP WebAPI与EasyUI结合增删改查之一(二十七)

    abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统——ABP总体介绍(一) abp(net core)+ ...

  4. ASP.NET CORE系列【三】使用Entity Framework Core进行增删改查

    身份验证 以前我们熟悉的web.config中配置的form验证,现在没有了.我们来看看在Core里面如何配置: 首先需要NuGet安装一个包:Microsoft.AspNetCore.Authent ...

  5. 国产化之路-统信UOS + Nginx + Asp.Net MVC + EF Core 3.1 + 达梦DM8实现简单增删改查操作

    专题目录 国产化之路-统信UOS操作系统安装 国产化之路-国产操作系统安装.net core 3.1 sdk 国产化之路-安装WEB服务器 国产化之路-安装达梦DM8数据库 国产化之路-统信UOS + ...

  6. Dapper逆天入门~强类型,动态类型,多映射,多返回值,增删改查+存储过程+事物案例演示

    Dapper的牛逼就不扯蛋了,答应群友做个入门Demo的,现有园友需要,那么公开分享一下: 完整Demo:http://pan.baidu.com/s/1i3TcEzj 注 意 事 项:http:// ...

  7. ASP.NET从零开始学习EF的增删改查

           ASP.NET从零开始学习EF的增删改查           最近辞职了,但是离真正的离职还有一段时间,趁着这段空档期,总想着写些东西,想来想去,也不是很明确到底想写个啥,但是闲着也是够 ...

  8. 构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(9)-MVC与EasyUI结合增删改查

    系列目录 文章于2016-12-17日重写 在第八讲中,我们已经做到了怎么样分页.这一讲主要讲增删改查.第六讲的代码已经给出,里面包含了增删改,大家可以下载下来看下. 这讲主要是,制作漂亮的工具栏,虽 ...

  9. 通过Java代码实现对数据库的数据进行操作:增删改查

    在写代码之前,依然是引用mysql数据库的jar包文件:右键项目-构建路径-设置构建路径-库-添加外部JAR 在数据库中我们已经建立好一个表xs :分别有xuehao  xingming    xue ...

随机推荐

  1. 使用C# (.NET Core) 实现观察者模式 (Observer Pattern) 并介绍 delegate 和 event

    观察者模式 这里面综合了几本书的资料. 需求 有这么个项目: 需求是这样的: 一个气象站, 有三个传感器(温度, 湿度, 气压), 有一个WeatherData对象, 它能从气象站获得这三个数据. 还 ...

  2. 【LiteOS】LiteOS任务篇-源码分析-创建任务函数

    目录 前言 链接 参考 笔录草稿 部分源码分析 源码分析 LOS_TaskCreate函数 LOS_TaskCreateOnly函数 宏 OS_TCB_FROM_PENDLIST 和 宏 LOS_DL ...

  3. 走进docker-swarm 带大家快速掌握docker自带编排工具

    什么是Docker Swarm? 对比Docker 前面我们介绍过Docker可以理解成是一个我们的服务的独立运行的容器,那么在实际工作中,我们的系统可能是一个微服务应用,系统中根据业务拆分成多个模块 ...

  4. VS2019 自定义项目模板

    前言: 使用"宇宙最强IDE"开发项目时,都需要根据不同情况选择一个项目模板,来满足开发需求:如下 VS为我们提供了基础的项目模板,但现有项目模板未包含基础功能如:日志输出.审计日 ...

  5. AutoAssign源码分析

    目录 AutoAssign源码分析 一. 简介 二. 论文理论 2.1 联合表示 2.2 正样本权重 2.3 负样本权重 2.4 总的loss 2.5 补充loss 三. 论文代码 四. 总结 五. ...

  6. 6.2set用法

    目录 1.set的定义 2.set容器内元素的访问 3.set常见使用的函数 set可以内部进行自动递增排序,且自动去除了重复元素 1.set的定义 set<typename> name; ...

  7. "Unmapped Spring configuration files found.Please configure Spring facet."解决办法

    最近在学习使用IDEA工具,觉得与Eclipse相比,还是有很多的方便之处. 但是,当把自己的一个项目导入IDEA之后,Event Log提示"Unmapped Spring configu ...

  8. 在 Docker Desktop 中启用 K8s 服务

    Overview 作为目前事实上的容器编排系统标准,K8s 无疑是现代应用的基石,很多同学入门可能直接就被卡到第一关,从哪去弄个 K8s 的环境 自己搭吧,要求的硬件资源太高,基本上搭建一个 K8s ...

  9. 日志收集之filebeat使用介绍

    此系列文章一共分为三部分,分为filebeat部分,logstash部分,es部分.这里会按照每天几百亿条的数据量来考虑,去设计.部署.优化这个日志系统,来最大限度的利用资源,并达到一个最优的性能.本 ...

  10. joda-time的简单使用及mysql时间函数的使用(今天,本周,本月)

    近期在做一些首页的统计数据复习了下mysql的时间函数,以及后续修改成 传入时间查询时使用的joda-time 软件简介 JodaTime 提供了一组Java类包用于处理包括ISO8601标准在内的d ...