ASP.NET 数据库编程终极指南
目录
-
(图片来源网络,侵删)- 1 技术栈选择
- 2 环境安装
- 3 创建第一个 ASP.NET Core 项目
-
- 1 什么是 ADO.NET?
- 2 ADO.NET 核心对象 (
SqlConnection,SqlCommand,SqlDataReader) - 3 完整代码示例:查询数据
- 4 使用
Dapper简化 ADO.NET
-
第三部分:现代 ORM - Entity Framework Core (EF Core)
- 1 什么是 ORM?为什么选择 EF Core?
- 2 EF Core 核心概念 (DbContext, DbSet, Model)
- 3 步骤一:安装 EF Core 包
- 4 步骤二:创建数据模型 (Entity)
- 5 步骤三:创建 DbContext
- 6 步骤四:配置数据库连接字符串
- 7 步骤五:创建并应用数据库迁移
- 8 步骤六:使用 EF Core 进行 CRUD 操作
- 8.1 查询数据
- 8.2 创建数据
- 8.3 更新数据
- 8.4 删除数据
-
- 1 依赖注入
- 2 异步编程 (
async/await) - 3 处理并发冲突
- 4 仓储模式
-
(图片来源网络,侵删)- 1 项目目标
- 2 创建项目与模型
- 3 设置数据库
- 4 创建控制器和视图
- 5 实现功能
第一部分:基础准备与环境搭建
1 技术栈选择
本教程将使用 .NET 6/7/8 (LTS) 和 ASP.NET Core MVC 框架,数据库方面,我们将以 SQL Server 为例,但大部分概念也适用于 PostgreSQL, MySQL, SQLite 等其他 EF Core 支持的数据库。
2 环境安装
- .NET SDK: 从 官网 下载并安装最新版的 .NET SDK (推荐 LTS 版本,如 .NET 8)。
- Visual Studio 2025: 从 官网 下载安装,在安装程序中,确保勾选了 “.NET 桌面开发” 或 “ASP.NET 和 Web 开发” 工作负载,这会自动安装 SQL Server Express LocalDB。
- SQL Server Management Studio (SSMS) (可选但推荐): 用于直接管理和查询数据库,从 官网 下载。
3 创建第一个 ASP.NET Core 项目
- 打开 Visual Studio 2025。
- 选择 “创建新项目”。
- 搜索并选择 “ASP.NET Core Web 应用” 模板,然后点击 “下一步”。
- 命名你的项目(
MyWebApp),选择一个位置,然后点击 “下一步”。 - 选择框架(.NET 8.0 或其他你安装的版本),不要勾选 “使用顶级语句”,然后点击 “创建”。
你已经有了一个可以运行的 ASP.NET Core 项目。
第二部分:核心概念 - ADO.NET
1 什么是 ADO.NET?
ADO.NET 是 .NET 框架中用于与数据源(如数据库)进行交互的一组类库,它是一个底层的、无状态的、基于连接的模型。
核心特点:
- 连接模型: 需要手动建立和关闭数据库连接。
- 高性能: 因为没有额外的抽象层,所以性能非常高。
- 灵活: 可以执行任何 SQL 命令,并精细控制数据访问过程。
2 ADO.NET 核心对象
SqlConnection: 代表与 SQL Server 数据库的连接。SqlCommand: 代表要执行的 SQL 命令(查询、更新、删除等)。SqlDataReader: 一个只读的、向前的数据流,用于高效读取查询结果。SqlDataAdapter: 用于填充DataSet或DataTable,实现离线数据操作。
3 完整代码示例:查询数据
假设我们有一个 Products 表,我们想从控制器中查询所有产品并传递给视图。
安装 NuGet 包
在解决方案资源管理器中,右键点击 “依赖项” -> “管理 NuGet 程序包”,搜索并安装 Microsoft.Data.SqlClient。
修改 HomeController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Data.SqlClient;
using System.Data;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration; // 需要注入 IConfiguration
namespace MyWebApp.Controllers
{
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task<IActionResult> Index()
{
var products = new List<Product>();
var connectionString = _configuration.GetConnectionString("DefaultConnection");
// 使用 using 语句确保资源被正确释放
using (var connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
var sql = "SELECT Id, Name, Price FROM Products";
using (var command = new SqlCommand(sql, connection))
{
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
products.Add(new Product
{
Id = reader.GetInt32(0),
Name = reader.GetString(1),
Price = reader.GetDecimal(2)
});
}
}
}
}
return View(products);
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
配置连接字符串
在 appsettings.json 中添加你的数据库连接字符串。
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=MyProductDb;Trusted_Connection=True;MultipleActiveResultSets=true"
},
// ... 其他配置
}
注意:你需要先在 SQL Server LocalDB 中创建一个名为 MyProductDb 的数据库,并手动创建 Products 表。
创建视图
在 Views/Home 文件夹下,右键 Index.cshtml,用以下代码替换:
@model IEnumerable<MyWebApp.Product>
<h1>产品列表</h1>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>名称</th>
<th>价格</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>@item.Id</td>
<td>@item.Name</td>
<td>@item.Price.ToString("C")</td>
</tr>
}
</tbody>
</table>
4 使用 Dapper 简化 ADO.NET
虽然 ADO.NET 很强大,但编写样板代码很繁琐。Dapper 是一个轻量级的“微ORM”,它可以在 ADO.NET 之上提供简单的扩展方法,让你用更少的代码完成同样的事情。
安装 Dapper
Install-Package Dapper
重写 HomeController 的 Index 方法
using Dapper;
using Microsoft.Data.SqlClient;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
namespace MyWebApp.Controllers
{
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
public async Task<IActionResult> Index()
{
var connectionString = _configuration.GetConnectionString("DefaultConnection");
var sql = "SELECT Id, Name, Price FROM Products";
using (var connection = new SqlConnection(connectionString))
{
// Dapper 的 Query<T> 方法会自动将查询结果映射到 List<T>
var products = await connection.QueryAsync<Product>(sql);
return View(products);
}
}
// ... Product 类同上
}
}
看到了吗?代码量大大减少!Dapper 非常适合对性能有极致要求,但又不希望像纯 ADO.NET 那样繁琐的场景。
第三部分:现代 ORM - Entity Framework Core (EF Core)
1 什么是 ORM?为什么选择 EF Core?
ORM (Object-Relational Mapping) 对象关系映射,是一种程序技术,用于把对象模型表示的对象映射到基于 SQL 的关系模型数据库结构上。
EF Core 的优势:
- 代码优先: 你只需定义 C# 类(模型),EF Core 会为你生成数据库架构。
- LINQ 查询: 使用 C# 的语言集成查询来查询数据库,而不是写原生 SQL。
- 自动变更追踪: 当你从数据库加载一个对象后,修改它的属性,EF Core 会自动知道哪些字段被改变了,从而生成正确的
UPDATE语句。 - 数据库迁移: 可以轻松地更新数据库架构以匹配你的模型。
- 解耦: 你的业务逻辑代码不依赖于特定的 SQL 语法,更容易测试和维护。
2 EF Core 核心概念
- Entity (实体): 对应数据库表的 C# 类(如
Product)。 - DbContext (上下文): 这是 EF Core 的核心,它负责与数据库交互,并跟踪实体的状态,它通常包含
DbSet<T>属性。 - DbSet: 代表数据库中的一个表,可以对它进行查询、添加、删除等操作。
3 步骤一:安装 EF Core 包
在 NuGet 包管理器控制台中运行:
# 对于 SQL Server Install-Package Microsoft.EntityFrameworkCore.SqlServer # 用于设计时创建迁移的包 Install-Package Microsoft.EntityFrameworkCore.Tools
4 步骤二:创建数据模型 (Entity)
在 Models 文件夹下创建 Product.cs:
// Models/Product.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyWebApp.Models
{
public class Product
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
我们添加了数据注解来验证和配置模型。
5 步骤三:创建 DbContext
在 Models 文件夹下创建 ApplicationDbContext.cs:
// Models/ApplicationDbContext.cs
using Microsoft.EntityFrameworkCore;
using MyWebApp.Models;
namespace MyWebApp.Models
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Product> Products { get; set; }
}
}
6 步骤四:配置数据库连接字符串
打开 Program.cs,将 DbContext 注册到依赖注入容器中。
// Program.cs
using Microsoft.EntityFrameworkCore;
using MyWebApp.Models;
var builder = WebApplication.CreateBuilder(args);
// 1. 添加服务到容器。
builder.Services.AddControllersWithViews();
// 2. 注册 DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
// ... 其余代码
7 步骤五:创建并应用数据库迁移
-
在 Visual Studio 的 “工具” 菜单中,打开 “NuGet 包管理器” -> “包管理器控制台”。
-
确保默认项目是你的 ASP.NET Core 项目。
-
运行以下命令:
# 创建初始迁移 Add-Migration InitialCreate # 将迁移应用到数据库 Update-Database
执行后,EF Core 会在你的数据库中自动创建一个
Products表。
8 步骤六:使用 EF Core 进行 CRUD 操作
我们可以修改 HomeController 来使用 EF Core。
修改 HomeController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyWebApp.Models;
using System.Threading.Tasks;
namespace MyWebApp.Controllers
{
public class HomeController : Controller
{
private readonly ApplicationDbContext _context;
// 通过构造函数注入 DbContext
public HomeController(ApplicationDbContext context)
{
_context = context;
}
// GET: /Home/Index
public async Task<IActionResult> Index()
{
// 使用 LINQ 查询,EF Core 会将其翻译成 SQL
var products = await _context.Products.ToListAsync();
return View(products);
}
// GET: /Home/Create
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Name,Price")] Product product)
{
if (ModelState.IsValid)
{
_context.Add(product);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(product);
}
// GET: /Home/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var product = await _context.Products.FindAsync(id);
if (product == null)
{
return NotFound();
}
return View(product);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,Name,Price")] Product product)
{
if (id != product.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(product);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ProductExists(product.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(product);
}
// GET: /Home/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var product = await _context.Products
.FirstOrDefaultAsync(m => m.Id == id);
if (product == null)
{
return NotFound();
}
return View(product);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var product = await _context.Products.FindAsync(id);
_context.Products.Remove(product);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool ProductExists(int id)
{
return _context.Products.Any(e => e.Id == id);
}
}
}
创建对应的视图 (Create.cshtml, Edit.cshtml, Delete.cshtml)
这些视图的创建方式与 Index.cshtml 类似,但包含一个 HTML 表单来输入数据,可以使用 Visual Studio 的 “添加视图” -> “Razor 视图 - 使用实体框架” 功能来自动生成这些视图,非常方便。
第四部分:最佳实践与高级技巧
1 依赖注入
我们已经看到了在 HomeController 中通过构造函数注入 ApplicationDbContext,这是 ASP.NET Core 推荐的做法,它使你的组件更易于测试和解耦。
2 异步编程 (async/await)
所有与数据库交互的 EF Core 和 Dapper 方法都提供了异步版本(以 Async ,在 Web 应用中,始终使用异步方法!这样可以避免阻塞 Web 请求线程,提高服务器的吞吐量和可伸缩性。
// 好的做法 var products = await _context.Products.ToListAsync(); // 不好的做法 (会阻塞线程) var products = _context.Products.ToList();
3 处理并发冲突
当多个用户同时尝试修改同一条数据时,可能会发生并发冲突,EF Core 通过 ConcurrencyCheck 或 RowVersion 属性来处理。
在模型中添加 Timestamp 属性:
[Timestamp]
public byte[] RowVersion { get; set; }
EF Core 会在 UPDATE 语句中包含此列,如果数据库中的值与从实体中读取的值不匹配,就会抛出 DbUpdateConcurrencyException,你可以在 Edit 方法中捕获此异常并提示用户。
4 仓储模式
对于大型项目,通常会创建一个仓储层来封装数据访问逻辑,进一步解耦控制器和 EF Core。
// 仓储接口
public interface IProductRepository
{
Task<IEnumerable<Product>> GetAllAsync();
Task<Product> GetByIdAsync(int id);
// ... 其他方法
}
// EF Core 实现的仓储
public class ProductRepository : IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context) => _context = context;
public async Task<IEnumerable<Product>> GetAllAsync() => await _context.Products.ToListAsync();
public async Task<Product> GetByIdAsync(int id) => await _context.Products.FindAsync(id);
// ...
}
// 在 Startup.cs/Program.cs 中注册仓储
builder.Services.AddScoped<IProductRepository, ProductRepository>();
// 在 Controller 中使用
public class ProductsController : Controller
{
private readonly IProductRepository _repository;
public ProductsController(IProductRepository repository) => _repository = repository;
// ...
}
第五部分:实战项目 - 构建一个简单的博客系统
这个项目将综合运用 EF Core 和 MVC 知识。
- 创建项目: 按照第一部分创建一个新的 ASP.NET Core MVC 项目。
- 创建模型:
Post.cs:Id,Title,Content,PublishDateTag.cs:Id,NamePostTag.cs(多对多关系):PostId,TagId
- 创建 DbContext:
BlogDbContext.cs,包含DbSet<Post>,DbSet<Tag>,DbSet<PostTag>。 - 配置依赖注入和迁移: 在
Program.cs中注册BlogDbContext,然后使用 PMC 创建并应用迁移。 - 创建控制器和视图:
PostsController: 实现列表、详情、创建、编辑、删除功能。- 为每个 Action 创建对应的 View。
- 添加路由和导航: 在
_Layout.cshtml中添加指向博客列表和创建新文章的链接。
这个项目将让你对整个数据流有更深刻的理解。
第六部分:总结与学习资源
- ADO.NET/Dapper: 底层、高性能、代码量多,适合性能要求极高或需要执行复杂/特定 SQL 的场景。
- Entity Framework Core: 现代、高效、开发效率高,绝大多数应用场景下的首选,它为你处理了大部分复杂性,让你能专注于业务逻辑。
学习资源
- 微软官方文档 (最权威):
- 视频教程:
- Philipp Bauknecht (德语,但代码通用): 他的 EF Core 教程非常深入。
- FreeCodeCamp: 有很多高质量的 ASP.NET Core 全栈教程。
- Udemy / Pluralsight: 搜索 "ASP.NET Core" 和 "Entity Framework Core",有很多付费和免费课程。
- 社区:
- Stack Overflow: 遇到问题,先搜索,大概率能找到答案。
- GitHub: 查看 EF Core 和 ASP.NET Core 的源码,了解内部实现。
希望这份详细的教程能帮助你顺利掌握 ASP.NET 数据库编程!祝你编码愉快!
