Visual Studio 2022 安装使用:Entity Framework Core

文章目录

  • 前言
  • [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的表,包含idnameagesalary列,应该执行如下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包

  1. 打开程序包管理器控制台:在 Visual Studio 2022 中,可以通过菜单 工具 > NuGet 包管理器 > 程序包管理器控制台 打开。

  2. 执行安装命令:在控制台中,输入上述表格中你需要的包的安装命令。例如,要安装 PostgreSQL 提供程序,如需安装多个包,重复此步骤即可,命令是:安装指定版本

    powershell 复制代码
    Install-Package Npgsql.EntityFrameworkCore.PostgreSQL -Version 3.1.2
  3. 验证安装:安装成功后,你可以在项目的"依赖项"下的"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

  • DbContextDataBase 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 包。

    powershell 复制代码
    Install-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 文件并获取连接字符串。

    csharp 复制代码
    using 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 包,执行以下指令:

    powershell 复制代码
    Install-Package Microsoft.Extensions.Configuration.EnvironmentVariables
  • C# 代码读取环境变量字符串

    csharp 复制代码
    using 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 语句,辅助调试和性能优化。操作步骤:

DbContextOnConfiguring 方法中添加日志配置(以用户提供的 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)数值类型(如 AgeSalary)无需额外配置,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() 附加实体:

    csharp 复制代码
    context.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方法,请参考下面链接

C# Linq常用方法


相关推荐
无限进步_5 小时前
深入理解C语言scanf函数:从基础到高级用法完全指南
c语言·开发语言·c++·后端·算法·visual studio
合作小小程序员小小店6 小时前
web开发,在线%蛋糕销售%管理系统,基于asp.net,webform,c#,sql server
开发语言·后端·asp.net·html5·教育电商
小龙报6 小时前
《算法通关指南数据结构和算法篇(3)--- 栈和stack》
开发语言·数据结构·c++·算法·创业创新·学习方法·visual studio
散峰而望1 天前
基本魔法语言分支和循环 (二) (C语言)
c语言·开发语言·github·visual studio
宝桥南山1 天前
.NET - .NET Aspire的Command-Line和GitHub Copilot
microsoft·微软·c#·asp.net·.net·.netcore
小龙报2 天前
《C语言疑难点 --- 字符函数和字符串函数专题(上)》
c语言·开发语言·c++·算法·学习方法·业界资讯·visual studio
小龙报2 天前
《数组和函数的实践游戏---扫雷游戏(基础版附源码)》
c语言·开发语言·windows·游戏·创业创新·学习方法·visual studio
Yupureki3 天前
从零开始的C++学习生活 12:AVL树全面解析
c语言·数据结构·c++·学习·visual studio
歪歪1003 天前
在C#中详细介绍一下Visual Studio中如何使用数据可视化工具
开发语言·前端·c#·visual studio code·visual studio·1024程序员节