【ASP.NET Core 基础知识】--数据库连接--使用Entity Framework Core进行数据库访问

一、介绍

Entity Framework Core(简称EF Core)是微软推出的一个轻量级版的Entity Framework,它是一个开源的、跨平台(Windows、Linux和macOS)的对象关系映射(ORM)框架。EF Core 旨在提供快速的数据访问和强大的数据库操作功能,同时保持较低的资源占用。
EF Core 支持与多种数据库系统的集成,包括 SQL Server、SQLite、MySQL、PostgreSQL 和 Oracle 等。它提供了 Code First 开发方法,允许开发人员通过代码来定义模型、配置映射关系和创建数据库。此外,EF Core 还支持数据迁移,使得在开发过程中数据库模式的变更更加容易管理和部署。
EF Core 与传统的 Entity Framework (EF) 相比,具有以下特点:

  1. 更轻量级: EF Core 比 EF 更为轻量,只包含了最核心的 ORM 功能,减少了不必要的依赖。
  2. 更高的性能: EF Core 设计上更加高效,能够提供更好的性能,特别是在执行大量数据操作时。
  3. 跨平台支持: EF Core 是 .NET Core 的一部分,因此可以在多种操作系统上运行,而 EF 主要针对 Windows 平台。
  4. 可扩展性: EF Core 提供了丰富的扩展机制,允许开发者自定义行为,如数据提供程序的创建。
  5. 兼容性: EF Core 可以与现有的 Entity Framework 应用集成,但并不完全兼容。

二、Entity Framework Core的基本概念

2.1 数据库提供程序

在 Entity Framework Core(EF Core)中,数据库提供程序(Database Provider)是一个关键组件,它负责将 EF Core 的通用功能与具体的数据库引擎进行连接。数据库提供程序允许 EF Core 与不同的数据库系统进行交互,并提供了访问这些数据库的必要接口和驱动程序。
数据库提供程序通常由数据库引擎的提供商或活跃的社区开发,并作为 EF Core 的一部分进行集成。例如,Microsoft 提供了针对 SQL Server 的官方提供程序,而 Entity Framework Core 社区提供了针对其他数据库系统的提供程序,如 MySQL 和 PostgreSQL。
数据库提供程序负责以下任务:

  1. 数据库连接: 提供程序必须提供连接到数据库的方法,并处理连接字符串。
  2. 数据操作: 提供程序需要实现与数据库进行交互的必要命令,包括查询、插入、更新和删除操作。
  3. 事务管理: 如果数据库支持事务,提供程序需要实现与 EF Core 事务模型的集成。
  4. 数据模型映射: 提供程序需要将 EF Core 数据模型映射到数据库模型(如表和视图)。
  5. 迁移支持: 提供程序需要支持 EF Core 的数据迁移功能,允许开发人员在数据库模式更改时创建迁移。
  6. 性能优化: 提供程序通常会针对特定数据库引擎进行优化,以提高数据访问性能。

EF Core 支持的数据库提供程序包括:

  • 官方提供的提供程序:
    • Microsoft.EntityFrameworkCore.SqlServer: 用于 SQL Server。
    • Microsoft.EntityFrameworkCore.Sqlite: 用于 SQLite。
  • 社区提供的提供程序:
    • Pomelo.EntityFrameworkCore.MySql: 用于 MySQL。
    • Npgsql.EntityFrameworkCore.PostgreSQL: 用于 PostgreSQL。
    • Oracle.EntityFrameworkCore: 用于 Oracle 数据库。

在选择使用 EF Core 时,开发者需要根据项目需求选择合适的数据库提供程序,并确保安装了相应的 NuGet 包。不同的提供程序可能具有不同的功能和性能特点,因此在实际应用中,选择一个与项目数据库相匹配的提供程序是非常重要的。

2.2 对象关系映射器(ORM)

对象关系映射(Object-Relational Mapping,简称 ORM)是一种软件设计技术,它通常用于实现面向对象编程语言里对象模型和关系数据库数据模型之间的相互转换。ORM 的主要目的是在关系数据库和业务实体对象之间做一个映射,使得开发者可以使用面向对象的方式来操作数据库,而不必直接编写 SQL 语句。

ORM 的核心概念包括:

  1. 对象(Objects): 在应用程序中表示业务实体。
  2. 关系(Relationships): 对象之间的交互和联系,例如一对多、一对一或多对多关系。
  3. 元数据(Metadata): 描述对象和关系的数据,通常存储在 XML 文件、注解或者专门的元数据类中。
  4. ORM 映射器(Mapper): 负责将对象映射到数据库中的表,以及将对象的属性映射到表的列。

ORM 框架的主要优点包括:

  • 提高了开发效率,因为开发者可以用熟悉的面向对象的方式来操作数据库。
  • 减少了编写和维护 SQL 语句的工作量。
  • 提高了代码的可读性和可维护性。
  • 通过 ORM 的查询构建器,可以编写类型安全且易于理解的查询。
  • 提供了对象之间的关系管理,如自动维护关联对象的状态。

ORM 框架的常见实现包括 Hibernate、Dapper、Entity Framework(EF)、Doctrine 等。这些框架通常支持多种数据库系统,并提供了强大的数据访问和持久化能力。
在 Entity Framework Core(EF Core)中,ORM 的概念依然适用,EF Core 提供了 ORM 功能,允许开发者使用 .NET 类型(如类和对象)来表示数据库中的表格和数据,而不需要直接与 SQL 语句打交道。EF Core 的 ORM 特性使得数据库操作更加直观和易于管理,同时提供了强大的查询、关系映射和性能优化机制。

2.3 Code First

Code First 是 Entity Framework(EF)的一个开发范式,它侧重于通过编写代码来定义模型(Model)和数据库架构,而不是依赖于图形界面或者配置文件来创建数据库实体。Code First 允许开发者以面向对象的方式设计数据库模型,并通过代码来配置映射关系,之后可以自动生成数据库架构。

Code First 的主要特点包括:

  1. 基于代码的设计: 开发者使用 .NET 类和属性来定义数据库模型,这些类和属性代表了数据库中的表和列。
  2. 数据模型控制: 开发者可以通过代码完全控制数据模型,包括添加、修改或删除实体和属性。
  3. 数据库迁移支持: Code First 允许开发者使用迁移(Migration)来管理数据库架构的变更,使得数据库模式的升级和回滚变得更加容易。
  4. 数据库生成: 开发者可以利用 Code First 创建新的数据库,或者与现有数据库集成。
  5. 灵活的数据注释: 使用 Code First 时,开发者可以在类和属性上使用特定的注释来配置映射和数据库行为。
  6. 数据操作简化: Code First 简化了数据操作,允许开发者使用 LINQ 或 Fluent API 进行查询和操作。

Code First 通常与以下两种模式结合使用:

  • 实体框架模型(Entity Framework Model): 开发者创建实体类,这些类通过 Fluent API 或数据注释与数据库表进行映射。
  • 代码优先迁移(Code First Migration): 开发者可以使用迁移来记录模型变更,并应用这些变更到数据库中。

使用 Code First 可以提高开发效率,并使得数据模型与代码的一致性更强。不过,Code First 通常需要开发者对 ORM 原理和数据库设计有一定的了解,才能更好地利用其优势。

三、使用Entity Framework Core进行数据库连接

在 Entity Framework Core(EF Core)中,连接数据库通常涉及以下步骤:

  1. 配置数据库提供程序。
  2. 创建DbContext类。
  3. 配置实体模型。
  4. 打开数据库连接。

以下是一个简单的示例,演示了如何使用EF Core连接到数据库:
首先,确保已经安装了适当的数据库提供程序包。例如,如果使用的是 SQL Server,需要安装 Microsoft.EntityFrameworkCore.SqlServer 包。

# 使用包管理器安装SQL Server提供程序包
dotnet add package Microsoft.EntityFrameworkCore.SqlServer

然后,你可以创建一个简单的 .NET 控制台应用程序,并在其中编写连接到数据库的代码。

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

namespace EFCoreSample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建一个新的DbContext实例
            using (var context = new MyDbContext())
            {
                // 创建或打开数据库连接
                context.Database.EnsureCreated(); // 创建数据库架构

                // 执行查询
                var blogs = context.Blogs.ToList();

                // 输出查询结果
                foreach (var blog in blogs)
                {
                    Console.WriteLine($"Blog ID: {blog.Id}, Title: {blog.Title}");
                }
            }

            Console.ReadKey();
        }
    }

    // DbContext 是一个关键类,它封装了对数据库的访问。
    // 你需要继承 DbContext 并配置它以使用你的数据模型。
    public class MyDbContext : DbContext
    {
        // 数据模型中定义的实体
        public DbSet<Blog> Blogs { get; set; }

        // 配置使用 SQL Server 数据库提供程序
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("Server=localhost;Database=SampleDB;Trusted_Connection=True;");
        }


        // 配置实体模型
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Blog>().HasKey(b => b.Id);
        }
    }

    // 定义一个实体类,表示数据库中的一条记录
    public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
    }
}

在这个例子中,我们创建了一个 MyDbContext 类,它继承自 DbContextMyDbContext 类配置了使用 SQL Server 数据库提供程序,并定义了一个名为 BlogsDbSet 属性,用于表示数据库中的 Blog 实体。
OnModelCreating 方法中,我们配置了 Blog 实体的主键。
Main 方法中,我们创建了一个 MyDbContext 实例,并使用 Database.EnsureCreated() 方法来创建数据库架构。然后,我们查询数据库并将结果输出到控制台。

四、Entity Framework Core的高级特性

4.1 数据迁移

Entity Framework Core(EF Core)的数据迁移是一种工具和过程,它允许开发者在数据库架构发生变化时,轻松地将新的架构应用到数据库中,同时保留现有的数据。数据迁移可以帮助你跟踪数据库架构的历史变更,并在开发和生产环境中应用这些变更。
数据迁移涉及以下几个关键概念:

  1. 迁移:迁移是数据库架构变更的记录。每次你修改数据模型并保存这些变更时,EF Core 都会创建一个新的迁移。
  2. 迁移历史记录:迁移历史记录是数据库中存储的迁移列表,它记录了应用于数据库的每个迁移。
  3. DbContext:DbContext 是 EF Core 中表示数据库连接和模型的类。每个 DbContext 实例都与一个数据库上下文关联,并且可以用于执行查询和修改数据库中的数据。
  4. DbSet:DbSet 是 DbContext 中表示数据库表的属性。每个 DbSet 表示一个表,并且可以用于查询和修改表中的数据。

下面是如何使用 EF Core 数据迁移的步骤:

  1. 添加迁移:使用 Add-Migration 命令添加新的迁移记录。这个命令会创建一个新的迁移类,并将其添加到迁移历史记录中。
    # 在包管理器控制台中执行以下命令
    Add-Migration "MyMigrationName"
    
  2. 应用迁移:使用 Update-Database 命令将新的迁移应用到数据库中。
    Update-Database
    
  3. 回滚迁移:如果需要,可以使用 Migration 命令回滚到先前的迁移状态。
    Update-Database -TargetMigration "PreviousMigrationName"
    
  4. 迁移脚本:可以使用 Script-Migration 命令生成一个 SQL 脚本,这个脚本包含了应用所有迁移所需的 SQL 语句。
    Script-Migration
    
  5. 迁移历史记录:可以在数据库中查看迁移历史记录,通常存储在 __EFMigrationsHistory 表中。

数据迁移是数据库版本控制的一种形式,可以帮助团队协作开发,确保数据库结构在开发和部署过程中保持一致。此外,数据迁移对于历史数据库架构变更的审计和回滚也很有用。

4.2 事务管理

在 Entity Framework Core(EF Core)中,事务管理允许开发者对一组相关数据库操作进行原子性处理,这意味着这些操作要么全部成功,要么全部回滚到最初的状态。EF Core 通过提供事务上下文支持数据库事务。
事务在 EF Core 中的使用涉及以下步骤:

  1. 开始事务:在 DbContext 实例中开启一个事务。
    using (var dbContextTransaction = context.Database.BeginTransaction())
    {
        try
        {
            // 在这里执行需要作为事务一部分的数据库操作
            // ...
    
            // 如果没有错误发生,则提交事务
            dbContextTransaction.Commit();
        }
        catch (Exception)
        {
            // 如果有错误发生,则回滚事务
            dbContextTransaction.Rollback();
        }
    }
    
  2. 提交事务:当所有操作都成功完成时,调用 Commit() 方法提交事务。
  3. 回滚事务:如果操作中发生错误,调用 Rollback() 方法回滚事务。

Tip:

  • 每个 DbContext 实例都有自己的事务上下文。
  • 事务仅适用于在同一 DbContext 实例中执行的操作。
  • 事务嵌套在 EF Core 中不受支持。

此外,EF Core 支持保存点(Savepoint),这是一种在事务中创建一个可回滚的子事务点的机制。如果操作失败,你可以回滚到最近创建的保存点,而不是回滚整个事务。
使用保存点的示例代码如下:

using (var dbContextTransaction = context.Database.BeginTransaction())
{
    try
    {
        // 创建一个保存点
        dbContextTransaction.CreateSavepoint("mySavepoint");

        // 在这里执行需要作为事务一部分的数据库操作
        // ...

        // 如果没有错误发生,则提交事务
        dbContextTransaction.Commit();
    }
    catch (Exception)
    {
        // 如果有错误发生,则回滚到最近的保存点
        dbContextTransaction.RollbackToSavepoint("mySavepoint");
    }
}

使用事务和保存点可以帮助你更好地控制数据库操作的原子性和错误处理。

4.3 性能优化

Entity Framework Core提供了很多高级特性来帮助开发者优化应用程序的性能。以下是一些可以用来提高EF Core性能的优化技巧:

  1. 使用正确的查询方式:根据查询需求选择合适的方法。例如,使用LINQ查询、原生SQL或存储过程。
  2. 延迟加载(Lazy Loading):默认情况下,EF Core 不会自动加载实体之间的导航属性。开启延迟加载功能可以提高性能,但可能会导致额外的数据库查询。
  3. 预加载相关实体:在查询时,通过使用Include或Explicit Loading来预加载相关实体,减少多次查询数据库的需要。
  4. 使用AsNoTracking:当不需要跟踪实体状态时,可以使用AsNoTracking方法提高性能。
  5. 批量操作:使用批处理技术,比如批量插入、更新和删除,以减少数据库交互次数。
  6. 使用内存缓存:对于那些不经常变化的数据,可以使用内存缓存来避免不必要的DB查询。
  7. 优化数据库模式:优化数据库表结构,如创建索引、使用分区表等,以加快查询速度。
  8. 使用内存映射文件:对于较大的数据集,可以使用内存映射文件来避免OutOfMemoryError。
  9. 使用事务:对于需要原子性操作的多个相关操作,使用事务可以提高数据的一致性和性能。
  10. 避免N+1查询问题:通过预加载相关实体来避免N+1查询问题,这是性能优化的一个常见问题。
  11. 使用Find方法:当需要获取一个已知主键的实体时,使用Find方法而不是FirstOrDefault或SingleOrDefault。
  12. 使用内存池:EF Core 3.0及更高版本引入了内存池技术,可以减少分配和垃圾回收的成本。
  13. 使用Value Generated On Add:对于某些列(如自增列),可以使用Value Generated On Add来避免插入时额外的查询。
  14. 使用Partial Methods:对于需要在上下文中执行的自定义操作,可以使用Partial Methods。
  15. 使用EF.Functions扩展方法:EF Core提供了EF.Functions扩展方法,可以执行数据库特定的操作。
  16. 使用性能分析工具:使用性能分析工具来识别瓶颈和执行效率低下的代码部分。
  17. 避免使用不必要的JOIN:JOIN操作可能会导致性能下降,尽量避免使用不必要的JOIN。
  18. 使用缓存的数据访问接口:使用缓存的数据访问接口来减少数据库访问次数。
  19. 使用异步操作:对于耗时的操作,使用异步操作可以提高应用程序的响应性。
  20. 使用数据库特定的优化:不同的数据库有不同的性能优化方法,了解并使用数据库特定的优化方法可以进一步提高性能。

这些性能优化技巧可以根据具体的应用场景和数据访问模式来选择性地应用。记住,性能优化是一个持续的过程,需要根据应用程序的具体需求和运行时的变化进行调整。

五、Entity Framework Core的跨数据库操作

Entity Framework Core (EF Core) 提供了跨数据库操作的能力,这意味着你可以在一个应用程序中使用不同的数据库引擎。为了实现跨数据库操作,你必须在 DbContext 中指定对应的数据库提供程序,并在 DbContext 构造函数中提供数据库连接字符串。
以下是一个简单的示例,演示了如何在 EF Core 中进行跨数据库操作:

  1. 安装相应数据库提供程序的 NuGet 包。例如,如果你要使用 SQL Server,你需要安装 Microsoft.EntityFrameworkCore.SqlServer
  2. 创建一个 DbContext 类,并为其指定数据库提供程序。例如,如果你要使用 SQL Server,你可以这样做:
using Microsoft.EntityFrameworkCore;

public class MyDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocalDB;Database=Blogging;Trusted_Connection=True;");
        }
    }

    public DbSet<Blog> Blogs { get; set; }
}

在这个例子中,我们使用了 UseSqlServer 方法来配置使用 SQL Server 提供程序。你需要替换连接字符串中的服务器地址、数据库名称、用户名和密码。
3. 接下来,你可以使用 DbContext 实例执行数据库操作。例如:

using (var context = new MyDbContext())
{
    // 执行数据库操作,例如查询数据
    var blog = context.Blogs.FirstOrDefault();

    // 或者添加、更新和删除数据
    context.Blogs.Add(new Blog { Url = "http://www.adventure-works.com" });
    context.SaveChanges();
}

请注意,你需要为每个数据库实例创建一个单独的 DbContext 实例。
如果你需要在应用程序中使用多个数据库,你可以创建多个 DbContext 实例,每个实例对应一个数据库。每个 DbContext 都会维护它自己的会话、缓存和工作线程。
确保在使用不同数据库的情况下,为每个 DbContext 配置正确的连接字符串。此外,不同的数据库可能需要不同的迁移和配置设置。在执行迁移时,你需要针对每个数据库单独运行迁移命令。
如果你需要在同一个 DbContext 实例中访问多个数据库,你可以通过在 DbContext 类中添加多个 DbSet 属性来实现这一点。每个 DbSet 属性对应一个数据库中的表。但是,这种方法可能会导致性能问题,因为每个 DbContext 实例只能有一个活动会话(session)。
在进行跨数据库操作时,请注意数据库之间的兼容性和性能差异。不同的数据库可能对查询的执行方式有不同的优化,因此在编写查询时,你可能需要根据所使用的数据库进行调整。
另外,需要注意的是,EF Core 的跨数据库操作功能可能并不完善,与单个数据库操作相比,性能也可能有所下降。在设计应用程序时,应当仔细评估是否真的需要跨数据库操作,并考虑其潜在的复杂性和性能影响。如果可能的话,尽量将应用程序设计为单一数据库方案,这样可以获得更好的性能和更简单的维护。

七、总结

文章介绍了如何使用Entity Framework Core (EF Core) 这个轻量级 ORM 框架进行数据库访问。文章首先介绍了EF Core的的基本概念,然后讲解了EF Core连接数据库,如何在多数据库环境下使用EF Core,以及需要注意的性能和兼容性问题。

你可能感兴趣的:(ASP.NET,Core,基础知识,asp.net,数据库,后端)