文章目录
- 前言
- [1. 介绍 Entity Framework Core](#1. 介绍 Entity Framework Core)
- [2. 安装 Entity Framework Core包](#2. 安装 Entity Framework Core包)
- [3. 使用 Entity Framework Core](#3. 使用 Entity Framework Core)
-
- [3.1 声明一个实体类](#3.1 声明一个实体类)
- [3.2 配置中间桥梁DbContext](#3.2 配置中间桥梁DbContext)
- [4. 配置数据库连接字符串,三种方式](#4. 配置数据库连接字符串,三种方式)
-
- [4.1 继承 DbContext类,配置数据库连接字符串](#4.1 继承 DbContext类,配置数据库连接字符串)
- [4.2 在appsettings.json 文件,配置数据库连接字符串](#4.2 在appsettings.json 文件,配置数据库连接字符串)
- [4.3 环境变量(不推荐)](#4.3 环境变量(不推荐))
- [5. 启用 EF Core 日志(关键调试工具)](#5. 启用 EF Core 日志(关键调试工具))
- [6. 简单使用 CRUD(增删改查)](#6. 简单使用 CRUD(增删改查))
-
- [6.1 创建操作(Create)](#6.1 创建操作(Create))
- 6.2.读取操作(Read)
- [6.3 更新操作(Update)](#6.3 更新操作(Update))
- [6.4. 删除操作(Delete)](#6.4. 删除操作(Delete))
- [C# Linq常用方法](# Linq常用方法)
前言
转载: 方程式sunny
视频教程: 跟着sunny老师学C#
源码: gitee仓库
1. 介绍 Entity Framework Core
EF Core 是什么 简单来说,就是实现代码中的类到数据库中表的映射的一种方法。 举个例子,假设我们要创建一个名为employees的表,包含id、name、age和salary列,应该执行如下sql语句:
sql
CREATE TABLE employee (
id INT PRIMARY KEY,
name VARCHAR(50),
age INT,
salary DECIMAL(10, 2)
);
- 如果想要通过
C#的ADO NET操作数据库,则更加麻烦,详情点击链接:通过C#代码连接数据库。 - 无论是直接通过
sql语句还是通过ADO NET都很不方便,如果表很多,那就barbecue了。 - 对于程序员而言,我们其实对于类很熟悉:
csharp
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public float Salary { get; set; }
}
EF core 就是能够将像上面的类通过C#代码直接转换成数据表,说的厉害一点就是将类映射到数据库表中,这样是不是比你写sql语句简单太多了。 当然,你可能会问,C# 中的int对应数据库中什么数据类型,string又对应什么类型,你说你操这个心干嘛?EF Core 会自己转换的。你可能又会问映射这种方式靠谱吗?会不会效率很低?靠谱,比我靠谱多了,也比多数程序员靠谱,你觉得设计这个框架的人会差吗?
2. 安装 Entity Framework Core包
-
打开程序包管理器控制台:在 Visual Studio 2022 中,可以通过菜单 工具 > NuGet 包管理器 > 程序包管理器控制台 打开。
-
执行安装命令:在控制台中,输入上述表格中你需要的包的安装命令。例如,要安装 PostgreSQL 提供程序,如需安装多个包,重复此步骤即可,命令是:安装指定版本
powershellInstall-Package Npgsql.EntityFrameworkCore.PostgreSQL -Version 3.1.2 -
验证安装:安装成功后,你可以在项目的"依赖项"下的"NuGet"文件夹中查看已安装的包 。

或者,右键项目,出现管理NuGet程序包,进行手动搜索查询安装



常用数据库提供程序包
| 数据库 | NuGet 包名 |
|---|---|
SQL Server |
Microsoft.EntityFrameworkCore.SqlServer |
SQLite |
Microsoft.EntityFrameworkCore.Sqlite |
MySQL |
Pomelo.EntityFrameworkCore.MySql |
PostgreSQL |
Npgsql.EntityFrameworkCore.PostgreSQL |
内存数据库 |
Microsoft.EntityFrameworkCore.InMemory |
3. 使用 Entity Framework Core
3.1 声明一个实体类
我们在 C# 里声明一个 Employee 实体类
csharp
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public float Salary { get; set; }
}

3.2 配置中间桥梁DbContext
Employee 类已经写好了,是不是可以直接映射了。还不行,因为数据库不知道 C# 代码,C# 代码也不认识数据库,它们两个想要建立连接,还需要通过一个关键桥梁 DbContext。

DbContext是DataBase Context的简写,翻译过来就是数据库上下文,这又是什么?你就把它当作一个名词来看待,它的作用是用来配置如何连接或者操作数据库的。DbContext官方已经写好了,我们直接继承该类使用。- 注意:我们在连接字符串中并没有配置数据库登录名和密码,这是因为
SQLServer登录有两种:Windows登录和SQLServer登录,前者不需要密码。
4. 配置数据库连接字符串,三种方式
新建一个 MyDbContext 类,继承 DbContext ,下面有三种方式,配置数据库连接字符串
4.1 继承 DbContext类,配置数据库连接字符串
可以在 DbContext 类的 OnConfiguring 方法中直接指定连接字符串,通过重写该方法来配置连接字符串,此时需要移除构造函数中对连接字符串的配置。
csharp
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace ConsoleApp1
{
internal class MyDbContext : DbContext
{
public DbSet<Employee> Employee { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 连接字符串格式
string connStr = "Host=localhost;Port=5432;Database=DB_Student;Username=postgres;Password=postgres";
optionsBuilder.UseNpgsql(connStr);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
}
}
}
4.2 在appsettings.json 文件,配置数据库连接字符串
将连接字符串存储在 appsettings.json 文件中,这是 .NET Core 应用程序的中央配置文件。
操作步骤:
-
(1) 安装包:在
NuGet包管理器控制台中执行以下命令,安装Microsoft.Extensions.Configuration.Json包。powershellInstall-package Microsoft.Extensions.Configuration.Json
-
(2) 添加文件:在项目根目录添加
appsettings.json文件,并在其中添加连接字符串。设置文件属性:右键点击appsettings.json文件,在属性中设置 "复制到输出目录" 为 "始终复制",确保编译后文件存在于输出目录。


bash{ "ConnectionStrings": { "PostgresConnection": "Host=localhost;Port=5432;Database=DB_Student;Username=postgres;Password=postgres" } } -
(3) 加载连接字符串:在
DbContext类的OnConfiguring方法中加载appsettings.json文件并获取连接字符串。csharpusing Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp1 { internal class MyDbContext : DbContext { public DbSet<Employee> Employee { get; set; } //protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) //{ // // 修正连接字符串格式 // string connStr = "Host=localhost;Port=5432;Database=DB_Student;Username=postgres;Password=postgres"; // optionsBuilder.UseNpgsql(connStr); //} protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var configBuilder = new ConfigurationBuilder() .AddJsonFile("appsettings.json") .Build(); var configSection = configBuilder.GetSection("ConnectionStrings"); var connectionString = configSection["PostgresConnection"] ?? null; optionsBuilder.UseNpgsql(connectionString); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } } }
4.3 环境变量(不推荐)
-
在
cmd中设置临时环境变量,这种设置的环境变量仅在当前终端会话中生效,关闭终端后,变量自动失效,属于临时环境变量。bash# Windows PowerShell $set ConnectionStrings__SQLServerConnection = "Server=.;Database=demo1;Trusted_Connection=True;Encrypt=false;" # Linux/macOS export ConnectionStrings__SQLServerConnection="Server=.;Database=demo1;Trusted_Connection=True;Encrypt=false;" -
在代码中读取环境变量,读取变量需要用到一个 `nuget 包,执行以下指令:
powershellInstall-Package Microsoft.Extensions.Configuration.EnvironmentVariables -
C#代码读取环境变量字符串csharpusing Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; namespace DbConnectionString.Entities { public class MyDbContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var config = new ConfigurationBuilder() .AddEnvironmentVariables() // 从环境变量加载配置 .Build(); var connectionString = config.GetConnectionString("SQLServerConnection"); optionsBuilder.UseSqlServer(connectionString); } } }
5. 启用 EF Core 日志(关键调试工具)
通过日志可以查看 EF Core 生成的 SQL 语句,辅助调试和性能优化。操作步骤:
在 DbContext 的 OnConfiguring 方法中添加日志配置(以用户提供的 MyDbContext 为例):
csharp
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 启用日志,输出到控制台
optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);
// 基于代码的连接字符串配置(SQL Server)
string connStr = "Server=.;Database=demo1;Trusted_Connection=True;Encrypt=false;";
optionsBuilder.UseSqlServer(connStr);
}
6. 简单使用 CRUD(增删改查)
6.1 创建操作(Create)
目标:向数据库插入新的 Employee 记录。
代码实现:
csharp
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1
{
public class Program
{
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
try
{
// 确保数据库创建
context.Database.EnsureCreated();
// 创建员工实体
var employee = new Employee
{
Id = 4,
Name = "张三",
Age = 30,
Salary = 15
};
// 添加到 DbSet(状态标记为 Added)
context.Employee.Add(employee);
// 提交变更(生成 INSERT 语句)
context.SaveChanges();
Console.WriteLine("员工创建成功!");
//打印所有
var employees = context.Employee.ToList();
foreach (var e in employees)
{
Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
}
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
}
Console.ReadLine();
}
}
}


关键点:
- (1)
DbSet<Employee> Employee作为实体容器,自动映射到数据库表Employee。 - (2)数值类型(如
Age、Salary)无需额外配置,EF Core自动处理类型映射。
6.2.读取操作(Read)
目标:查询单个员工信息及批量过滤查询。
代码实现:
csharp
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1
{
public class Program
{
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
try
{
// 确保数据库创建
context.Database.EnsureCreated();
//// 创建员工实体
//var employee = new Employee
//{
// Id = 4,
// Name = "张三",
// Age = 30,
// Salary = 15
//};
//// 添加到 DbSet(状态标记为 Added)
//context.Employee.Add(employee);
//// 提交变更(生成 INSERT 语句)
//context.SaveChanges();
//Console.WriteLine("员工创建成功!");
////打印所有
//var employees = context.Employee.ToList();
//foreach (var e in employees)
//{
// Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
//}
//查找Id为1
var employee1 = context.Employee.Find(1);
Console.WriteLine($"ID: {employee1.Id}, Name: {employee1.Name}, Age: {employee1.Age}, Salary: {employee1.Salary}");
// 复杂查询:查询薪资大于 10000 且年龄小于 40 的员工,按薪资降序排列
var highSalaryEmployees = context.Employee
.Where(e => e.Salary > 10 && e.Age < 40)
.OrderByDescending(e => e.Salary)
.ToList();
// 输出结果
Console.WriteLine("高薪员工列表:");
foreach (var e in highSalaryEmployees)
{
Console.WriteLine($"ID: {e.Id}, 姓名: {e.Name}, 薪资: {e.Salary:C}");
}
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
}
Console.ReadLine();
}
}
}

关键点:
- (1)
Find()方法仅适用于主键查询,性能优于FirstOrDefault(e => e.Id == 1)。 - (2)
LINQ查询支持链式操作,Where()过滤条件、OrderBy()排序等操作会生成对应的SQL语句。
6.3 更新操作(Update)
目标:修改员工的薪资和年龄。
代码实现:
csharp
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1
{
public class Program
{
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
try
{
// 确保数据库创建
context.Database.EnsureCreated();
//// 创建员工实体
//var employee = new Employee
//{
// Id = 4,
// Name = "张三",
// Age = 30,
// Salary = 15
//};
//// 添加到 DbSet(状态标记为 Added)
//context.Employee.Add(employee);
//// 提交变更(生成 INSERT 语句)
//context.SaveChanges();
//Console.WriteLine("员工创建成功!");
////打印所有
//var employees = context.Employee.ToList();
//foreach (var e in employees)
//{
// Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
//}
//查找Id为1
//var employee1 = context.Employee.Find(1);
//Console.WriteLine($"ID: {employee1.Id}, Name: {employee1.Name}, Age: {employee1.Age}, Salary: {employee1.Salary}");
//// 复杂查询:查询薪资大于 10000 且年龄小于 40 的员工,按薪资降序排列
//var highSalaryEmployees = context.Employee
// .Where(e => e.Salary > 10 && e.Age < 40)
// .OrderByDescending(e => e.Salary)
// .ToList();
//// 输出结果
//Console.WriteLine("高薪员工列表:");
//foreach (var e in highSalaryEmployees)
//{
// Console.WriteLine($"ID: {e.Id}, 姓名: {e.Name}, 薪资: {e.Salary:C}");
//}
// 获取已追踪的实体(通过查询或 Find())
var employee1 = context.Employee.Find(1);
if (employee1 != null)
{
// 修改属性(状态自动标记为 Modified)
employee1.Salary = 16000.0f;
employee1.Age = 31;
// 提交变更(生成 UPDATE 语句)
context.SaveChanges();
Console.WriteLine("员工信息更新成功!");
}
//打印所有
var employees = context.Employee.ToList();
foreach (var e in employees)
{
Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
}
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
}
Console.ReadLine();
}
}
}


关键点:
-
(1)直接修改已追踪实体的属性,
EF Core会自动检测变更并生成UPDATE语句。 -
(2)若实体未被追踪(如从其他上下文获取),需先调用
Attach()附加实体:csharpcontext.Employees.Attach(employee); // 附加到当前上下文 context.Entry(employee).State = EntityState.Modified; // 显式标记为修改
6.4. 删除操作(Delete)
目标:删除指定员工记录。
代码实现:
csharp
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
namespace ConsoleApp1
{
public class Program
{
static void Main(string[] args)
{
using (var context = new MyDbContext())
{
try
{
// 确保数据库创建
context.Database.EnsureCreated();
//// 创建员工实体
//var employee = new Employee
//{
// Id = 4,
// Name = "张三",
// Age = 30,
// Salary = 15
//};
//// 添加到 DbSet(状态标记为 Added)
//context.Employee.Add(employee);
//// 提交变更(生成 INSERT 语句)
//context.SaveChanges();
//Console.WriteLine("员工创建成功!");
////打印所有
//var employees = context.Employee.ToList();
//foreach (var e in employees)
//{
// Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
//}
//查找Id为1
//var employee1 = context.Employee.Find(1);
//Console.WriteLine($"ID: {employee1.Id}, Name: {employee1.Name}, Age: {employee1.Age}, Salary: {employee1.Salary}");
//// 复杂查询:查询薪资大于 10000 且年龄小于 40 的员工,按薪资降序排列
//var highSalaryEmployees = context.Employee
// .Where(e => e.Salary > 10 && e.Age < 40)
// .OrderByDescending(e => e.Salary)
// .ToList();
//// 输出结果
//Console.WriteLine("高薪员工列表:");
//foreach (var e in highSalaryEmployees)
//{
// Console.WriteLine($"ID: {e.Id}, 姓名: {e.Name}, 薪资: {e.Salary:C}");
//}
//// 获取已追踪的实体(通过查询或 Find())
//var employee1 = context.Employee.Find(1);
//if (employee1 != null)
//{
// // 修改属性(状态自动标记为 Modified)
// employee1.Salary = 16000.0f;
// employee1.Age = 31;
// // 提交变更(生成 UPDATE 语句)
// context.SaveChanges();
// Console.WriteLine("员工信息更新成功!");
//}
////打印所有
//var employees = context.Employee.ToList();
//foreach (var e in employees)
//{
// Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
//}
// 获取要删除的实体(需存在于上下文中)
var employee = context.Employee.FirstOrDefault(e => e.Id == 2);
if (employee != null)
{
// 标记为删除(状态设为 Deleted)
context.Employee.Remove(employee);
// 提交变更(生成 DELETE 语句)
context.SaveChanges();
Console.WriteLine("员工记录删除成功!");
}
//打印所有
var employees = context.Employee.ToList();
foreach (var e in employees)
{
Console.WriteLine($"ID: {e.Id}, Name: {e.Name}, Age: {e.Age}, Salary: {e.Salary}");
}
}
catch (Exception ex)
{
Console.WriteLine($"错误: {ex.Message}");
}
}
Console.ReadLine();
}
}
}


关键点:
- (1)删除操作需先确保实体已被当前
DbContext追踪(通过查询或Attach()附加)。 - (2)若存在外键关联,需先处理依赖关系(如级联删除),否则会抛出
DbUpdateException。
C# Linq常用方法
更多的 EF Core方法,请参考下面链接