准备使用 Entity Framework Core(数据库优先)访问 SQL ServerPrepare to access SQL Server using Entity Framework Core (database-first)

更新页 :
页面创建日期 :

操作环境

Visual Studio的
  • Visual Studio 2022
。网
  • .NET 8
实体框架核心
  • 实体框架核心 8.0
SQL 服务器
  • SQL Server 2022

* 以上是一个验证环境,但它可能适用于其他版本。

起先

Entity Framework Core 是一个 O/R 映射器库。 在访问数据库时,您可以通过代码中定义的模型(类)访问数据库的记录,而无需直接使用SQL语句。 这提供了以下好处:

  • 由于SQL语句不是直接编写的,因此减少了SQL注入等安全风险。
  • 由于 SQL 语句是字符串,因此即使语法错误,也不会检查构建错误,但由于模型是程序语法,因此可以在构建时检查错误。

Entity Framework Core 可以从现有数据库自动生成代码,以连接到这些模型和数据库。 相反,有一种方法可以手动编写代码,然后自动生成数据库。

前者称为“数据库优先”,后者称为“代码优先”。 还有“模型优先”,它从 ER 图等蓝图生成代码和数据库,但它在 Entity Framework Core 中并未广泛使用。

在本例中,我们将使用“数据库优先”模式,该模式在数据库已存在的基础上生成代码。

SQL Server 设置

为了访问此提示中的 SQL Server 数据库,请提前设置 SQL Server。 它可以在开发环境中的 PC 上设置,也可以通过网络在另一台 PC 上设置。 如果可以从开发环境连接到 SQL Server,那么就可以开始了。 在此提示中,SQL Server 安装在单独的环境中。

SQL Server 设置步骤被省略,因为它们是冗余的。 以下页面包含与 SQL Server 相关的提示,因此,如果您想了解如何设置它,请参考它。

创建表

这一次,我们将以 Mr./Ms. 的身份创建以下数据库和表。

  • 数据库名称:TestDatabase
  • 表名:用户
  • 表列:[ID]、[名称]、[密码]、[年龄]、[电子邮件]、[生日]、[UpdateDateTime]

您可以以任何方式创建它,但如果您不想这样做,请针对 SQL Server 运行以下 SQL 来生成它。

以下是数据库创建 SQL,但由于数据库创建的路径会根据版本等而变化,因此使用 GUI 或命令而不是 SQL 创建它可能更可靠。

USE [master]
GO
CREATE DATABASE [TestDatabase]
 CONTAINMENT = NONE
 ON  PRIMARY 
( NAME = N'TestDatabase', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\TestDatabase.mdf' , SIZE = 8192KB , MAXSIZE = UNLIMITED, FILEGROWTH = 65536KB )
 LOG ON 
( NAME = N'TestDatabase_log', FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL16.MSSQLSERVER\MSSQL\DATA\TestDatabase_log.ldf' , SIZE = 8192KB , MAXSIZE = 2048GB , FILEGROWTH = 65536KB )
 WITH CATALOG_COLLATION = DATABASE_DEFAULT, LEDGER = OFF
GO
ALTER DATABASE [TestDatabase] SET COMPATIBILITY_LEVEL = 160
GO
IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
begin
EXEC [TestDatabase].[dbo].[sp_fulltext_database] @action = 'enable'
end
GO
ALTER DATABASE [TestDatabase] SET ANSI_NULL_DEFAULT OFF 
GO
ALTER DATABASE [TestDatabase] SET ANSI_NULLS OFF 
GO
ALTER DATABASE [TestDatabase] SET ANSI_PADDING OFF 
GO
ALTER DATABASE [TestDatabase] SET ANSI_WARNINGS OFF 
GO
ALTER DATABASE [TestDatabase] SET ARITHABORT OFF 
GO
ALTER DATABASE [TestDatabase] SET AUTO_CLOSE OFF 
GO
ALTER DATABASE [TestDatabase] SET AUTO_SHRINK OFF 
GO
ALTER DATABASE [TestDatabase] SET AUTO_UPDATE_STATISTICS ON 
GO
ALTER DATABASE [TestDatabase] SET CURSOR_CLOSE_ON_COMMIT OFF 
GO
ALTER DATABASE [TestDatabase] SET CURSOR_DEFAULT  GLOBAL 
GO
ALTER DATABASE [TestDatabase] SET CONCAT_NULL_YIELDS_NULL OFF 
GO
ALTER DATABASE [TestDatabase] SET NUMERIC_ROUNDABORT OFF 
GO
ALTER DATABASE [TestDatabase] SET QUOTED_IDENTIFIER OFF 
GO
ALTER DATABASE [TestDatabase] SET RECURSIVE_TRIGGERS OFF 
GO
ALTER DATABASE [TestDatabase] SET  DISABLE_BROKER 
GO
ALTER DATABASE [TestDatabase] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
GO
ALTER DATABASE [TestDatabase] SET DATE_CORRELATION_OPTIMIZATION OFF 
GO
ALTER DATABASE [TestDatabase] SET TRUSTWORTHY OFF 
GO
ALTER DATABASE [TestDatabase] SET ALLOW_SNAPSHOT_ISOLATION OFF 
GO
ALTER DATABASE [TestDatabase] SET PARAMETERIZATION SIMPLE 
GO
ALTER DATABASE [TestDatabase] SET READ_COMMITTED_SNAPSHOT OFF 
GO
ALTER DATABASE [TestDatabase] SET HONOR_BROKER_PRIORITY OFF 
GO
ALTER DATABASE [TestDatabase] SET RECOVERY FULL 
GO
ALTER DATABASE [TestDatabase] SET  MULTI_USER 
GO
ALTER DATABASE [TestDatabase] SET PAGE_VERIFY CHECKSUM  
GO
ALTER DATABASE [TestDatabase] SET DB_CHAINING OFF 
GO
ALTER DATABASE [TestDatabase] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) 
GO
ALTER DATABASE [TestDatabase] SET TARGET_RECOVERY_TIME = 60 SECONDS 
GO
ALTER DATABASE [TestDatabase] SET DELAYED_DURABILITY = DISABLED 
GO
ALTER DATABASE [TestDatabase] SET ACCELERATED_DATABASE_RECOVERY = OFF  
GO
EXEC sys.sp_db_vardecimal_storage_format N'TestDatabase', N'ON'
GO
ALTER DATABASE [TestDatabase] SET QUERY_STORE = ON
GO
ALTER DATABASE [TestDatabase] SET QUERY_STORE (OPERATION_MODE = READ_WRITE, CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30), DATA_FLUSH_INTERVAL_SECONDS = 900, INTERVAL_LENGTH_MINUTES = 60, MAX_STORAGE_SIZE_MB = 1000, QUERY_CAPTURE_MODE = AUTO, SIZE_BASED_CLEANUP_MODE = AUTO, MAX_PLANS_PER_QUERY = 200, WAIT_STATS_CAPTURE_MODE = ON)
GO
ALTER DATABASE [TestDatabase] SET  READ_WRITE 
GO

表创建 SQL。

USE [TestDatabase]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[User](
  [ID] [int] NOT NULL,
  [Name] [nvarchar](20) NOT NULL,
  [Password] [nvarchar](20) NOT NULL,
  [Age] [int] NULL,
  [Email] [nvarchar](200) NULL,
  [Birthday] [date] NULL,
  [UpdateDateTime] [datetime2](7) NULL,
  CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
  [ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

记录追加 SQL。

USE [TestDatabase]
GO
INSERT [dbo].[User] ([ID], [Name], [Password], [Age], [Email], [Birthday], [UpdateDateTime]) VALUES (1, N'氏名1', N'aaaa', 20, N'aaaa@example.com', CAST(N'2020-04-01' AS Date), CAST(N'2021-03-14T00:00:00.0000000' AS DateTime2))
GO
INSERT [dbo].[User] ([ID], [Name], [Password], [Age], [Email], [Birthday], [UpdateDateTime]) VALUES (2, N'氏名2', N'bbbb', 30, N'bbbb@example.com', CAST(N'2010-04-01' AS Date), CAST(N'2021-03-14T00:00:00.0000000' AS DateTime2))
GO

Visual Studio 设置

我们假设您也已经设置了此设置。 如果您想了解设置步骤等,请在下一页进行总结。

创建项目

Entity Framework Core 不依赖于任何特定的执行环境,因此可以在许多项目中使用。 在本文中,我们将在简单的控制台应用程序环境中使用 Entity Framework Core。

在新项目中,选择“控制台应用”。

项目已创建。 项目名称是什么并不重要。

获取 Entity Framework Core 包

获取用于将 Entity Framework Core 与 NuGet 配合使用的包。

右键单击依赖项,然后选择“管理 NuGet 包”。

从选项卡中选择“浏览”后,输入 EntityFrameworkCore 搜索字段。 然后,应在列表中看到与 Entity Framework Core 相关的包。

由于这次我们将使用 SQL Server,因此我们将安装以下包。

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.Tools
  • Microsoft.EntityFrameworkCore.SqlServer

Microsoft.EntityFrameworkCore在此示例中,我们将安装 . 同时安装其他两个。

选择安装目标,然后单击“安装”按钮。 对于版本,请选择最新的稳定版本。

对话框基本上没问题,您可以单击“确定”。

同时安装其他两个。

我认为包看起来像这样:

从数据库表结构创建模型(代码)

若要自动生成模型和其他代码,请先生成项目以确保没有错误。 如果出现错误,模型创建将失败。 如果已验证没有错误,则无需生成它。

在 Visual Studio 中,打开包管理器控制台。 如果没有,可以从菜单“工具”、“NuGet 包管理器”、“包管理器控制台”中打开它。

将显示以下窗口,因此请确保右上角的“默认项目”是您要为其创建模型的项目。 (如果你有多个项目,你需要小心)

在输入字段中输入以下文本: 参数会根据环境而变化,因此请及时按照以下说明进行更改。

Scaffold-DbContext -Provider Microsoft.EntityFrameworkCore.SqlServer -Connection "Data Source=<サーバー名>\<インスタンス名>;Database=<データメース名>;user id=<接続ユーザー名>;password=<接続パスワード>;TrustServerCertificate=true" -f -OutputDir "<出力フォルダパス>" -Context "<コンテキストクラス名>" -UseDatabaseNames -DataAnnotations -NoPluralize

示例输入

Scaffold-DbContext -Provider Microsoft.EntityFrameworkCore.SqlServer -Connection "Data Source=TestServer;Database=TestDatabase;user id=TestUser;password=pass;TrustServerCertificate=true" -f -OutputDir "Models\Database" -Context "TestDatabaseDbContext" -UseDatabaseNames -DataAnnotations -NoPluralize
参数 说明参数 示例
供应商 对于 SQL Server,它是 Microsoft.EntityFrameworkCore.SqlServer 固定的。 Microsoft.EntityFrameworkCore.SqlServer
连接 要连接到数据库的连接字符串。 连接字符串可以与其他应用一起使用,因此请按照连接字符串的表示法指定要指定的内容。 可以使用 Windows 身份验证或 SQL Server 身份验证。 顺便说一下,它只是暂时用于创建模型,因此在发布此连接字符串的应用程序后,无需注意安全性。 如果您的密码中有符号,请小心逃逸。 “数据源 = ServerName\SQLEXPRESS; Database=TestDatabase; 用户 id=用户名; 密码=**********”
f 即使程序已经存在,它也会被强行覆盖。 没有<>
输出目录 要输出代码的文件夹路径。 相对于项目文件夹的路径 模型\数据库
上下文 使用实体框架时的上下文类名称 TestDatabaseDbContext
UseDatabaseNames(使用数据库名称) 如果指定,则数据库的表名将按原样为类名。 如果未指定,则根据规则调整实体类名的大小写。 没有<>
DataAnnotations 指定后,列类型会自动将 DataAnnotation 特性追加到每个属性。 如果您想根据数据库类型自动执行输入检查,这将有点用。 没有<>
Namespace 生成的实体类所属的命名空间。 如果未指定,则根据文件夹确定命名空间。 Test命名空间
Context命名空间 生成的 Context 所属的命名空间。 如果未指定,则根据文件夹确定命名空间。 Test命名空间
NoOnConfiguring 不要在代码中嵌入原始连接字符串。 没有<>
NoPluralize 确保 Context 中每个表名的属性名称不是复数形式。 没有<>

当您按 Enter 键运行它时,将自动生成代码: 如果发生错误,将显示原因,因此请根据错误内容进行响应。

User 该表的模型代码如下。

using System.ComponentModel.DataAnnotations;

namespace SetupSqlServerDatabaseFirst.Models.Database;

public partial class User
{
  [Key]
  public int ID { get; set; }

  [StringLength(20)]
  public string Name { get; set; } = null!;

  [StringLength(20)]
  public string Password { get; set; } = null!;

  public int? Age { get; set; }

  [StringLength(200)]
  public string? Email { get; set; }

  public DateOnly? Birthday { get; set; }

  public DateTime? UpdateDateTime { get; set; }
}

顺便说一下,之所以显示警告,是因为连接字符串是按原样在生成的上下文类的代码中编写的。 如果可能,连接字符串应存储在单独的位置,并在运行时进行设置,但在这种情况下,它是为了检查操作,因此我将保持原样。

尝试检索和显示记录

现在我们有了访问数据库中记录的代码,让我们尝试检索记录并在控制台上显示它们。

Program.cs 并按如下方式进行修改。

// See https://aka.ms/new-console-template for more information
using SetupSqlServerDatabaseFirst.Models.Database;
using System.Text.Json;

Console.WriteLine("Hello, World!");

// データベースコンテキストのインスタンスを生成する
using var dbContext = new TestDatabaseDbContext();

// データベースから User 一覧を取得する
var users = dbContext.User.ToList();

// 取得した User 情報をコンソールに書き出す
foreach (var user in users)
{
  Console.WriteLine(JsonSerializer.Serialize(user));
}

在 中生成自动生成的 DbContextnew 。 它被声明为可以自动销毁数据库连接 using var

dbContext 生成属性以访问每个模型,因此在本例 User 中,您可以通过访问属性来 User 操作表中的记录。 发出的 SQL 是内部自动生成的,不需要注意。

ToList这里,使用扩展方法来User检索表中的所有记录。

foreach其余部分是使用 and JsonSerializer.Serialize 方法User在控制台上显示信息来完成的。 如User上所述,表中的每一列都声明为一个属性,因此可以单独检索该值。