在.NET应用程序开发中,将数据录入数据库是一项基础且至关重要的任务,无论是记录用户信息、保存订单详情还是存储系统日志,都离不开与数据库的交互。.NET生态系统提供了多种强大且灵活的方式来完成这项工作,从底层的ADO.NET到现代的对象关系映射(ORM)框架,如Entity Framework Core,本文将详细介绍在.NET中实现数据录入的核心方法、关键概念及最佳实践。

核心概念与准备工作
在开始编写代码之前,理解几个核心概念是必不可少的,这些概念构成了所有数据库操作的基础。
连接字符串
连接字符串是包含数据库连接信息的文本,它告诉应用程序如何找到并连接到数据库服务器,一个典型的SQL Server连接字符串如下:
"Server=my_server_address;Database=my_database;User Id=my_user;Password=my_password;"
这个字符串包含了服务器地址、数据库名称、用户凭据等关键信息,在实际项目中,出于安全和灵活性考虑,通常会将连接字符串存储在配置文件(如appsettings.json)中,而不是硬编码在代码里。
命令对象
命令对象(如ADO.NET中的SqlCommand)负责执行对数据库的操作,它持有要执行的SQL语句(如INSERT, UPDATE, DELETE)或存储过程的名称,以及可能需要的参数。
参数化查询 这是防止SQL注入攻击的关键安全措施,SQL注入是一种通过在输入字段中插入恶意SQL代码来攻击数据库的技术,参数化查询通过将SQL命令与用户输入分开处理,确保输入数据仅被当作字面值处理,从而彻底杜绝了SQL注入的风险,不应使用字符串拼接来构建SQL,而应使用参数。
使用 ADO.NET
ADO.NET是.NET框架中用于数据访问的底层技术,它提供了对数据库操作的直接控制,虽然代码相对繁琐,但性能优异,是理解数据库交互原理的最佳方式。
以下是一个使用ADO.NET向Users表中插入一条新记录的完整示例:
using System;
using System.Data;
using System.Data.SqlClient;
public class AdoNetExample
{
public void AddUser(string connectionString, string userName, string userEmail)
{
// 定义INSERT语句,使用@符号作为参数占位符
string sql = "INSERT INTO Users (Name, Email, CreatedAt) VALUES (@Name, @Email, @CreatedAt)";
// 使用'using'语句确保连接和命令对象被正确释放
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (SqlCommand command = new SqlCommand(sql, connection))
{
// 添加参数并赋值
command.Parameters.AddWithValue("@Name", userName);
command.Parameters.AddWithValue("@Email", userEmail);
command.Parameters.AddWithValue("@CreatedAt", DateTime.Now);
try
{
// 打开连接
connection.Open();
// ExecuteNonQuery用于执行不返回结果集的命令(如INSERT, UPDATE, DELETE)
int rowsAffected = command.ExecuteNonQuery();
Console.WriteLine($"成功插入 {rowsAffected} 行数据。");
}
catch (SqlException ex)
{
// 捕获并处理数据库相关的异常
Console.WriteLine($"数据库错误: {ex.Message}");
}
} // command对象在此处被自动释放
} // connection对象在此处被自动释放
}
}
代码解析:

using语句:确保SqlConnection和SqlCommand等非托管资源在使用完毕后被自动关闭和释放,即使发生异常也不例外。- 参数化:
@Name,@Email,@CreatedAt是参数占位符。command.Parameters.AddWithValue()方法为这些参数提供安全的值。 ExecuteNonQuery():此方法执行命令并返回受影响的行数,对于INSERT操作,这通常是1。
使用 Entity Framework Core
Entity Framework (EF) Core 是一个轻量级、可扩展且跨平台的ORM框架,它允许开发者使用.NET对象来操作数据库,而无需编写大部分SQL代码,EF Core会自动将对象的变更转换为相应的数据库命令。
你需要定义一个实体模型和一个数据库上下文。
// 1. 定义实体模型
public class User
{
public int Id { get; set; } // 主键
public string Name { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; }
}
// 2. 定义数据库上下文
public class MyDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }
}
你可以通过以下方式轻松地插入数据:
using Microsoft.EntityFrameworkCore;
public class EfCoreExample
{
public void AddUser(MyDbContext context, string userName, string userEmail)
{
try
{
// 创建一个新的User实体对象
var newUser = new User
{
Name = userName,
Email = userEmail,
CreatedAt = DateTime.Now
};
// 将新实体添加到DbContext的Users集合中
context.Users.Add(newUser);
// 调用SaveChangesAsync,EF Core会生成并执行INSERT语句
await context.SaveChangesAsync();
Console.WriteLine("用户信息已通过EF Core成功保存。");
}
catch (DbUpdateException ex)
{
Console.WriteLine($"数据库更新错误: {ex.InnerException?.Message ?? ex.Message}");
}
}
}
代码解析:
- 面向对象:你操作的是
User对象,而不是直接处理SQL和连接。 - 变更跟踪:当你调用
context.Users.Add()时,EF Core开始跟踪这个新对象的状态。 SaveChangesAsync():此方法会检查所有被跟踪的实体变更,生成相应的SQL命令(这里是INSERT),并在一个事务中执行它们,使用异步版本有助于提高应用程序的响应能力和可伸缩性。
最佳实践与高级考量
防止SQL注入 如前所述,永远不要通过字符串拼接来构建SQL查询。
// 错误的方式 - 极易受到SQL注入攻击
string sql = $"INSERT INTO Users (Name) VALUES ('{userName}')";
// 正确的方式 - 使用参数化查询
string sql = "INSERT INTO Users (Name) VALUES (@Name)";
command.Parameters.AddWithValue("@Name", userName);
使用异步编程
在现代.NET应用中,尤其是在Web应用(如ASP.NET Core)或UI应用中,应优先使用异步方法(如ExecuteNonQueryAsync, SaveChangesAsync)来避免阻塞线程,从而提升应用的性能和用户体验。
事务处理 当需要将多个数据库操作作为一个原子单元(要么全部成功,要么全部失败)来执行时,应使用事务。

// ADO.NET事务示例
using (var transaction = connection.BeginTransaction())
{
try
{
// 执行多个命令...
command.Transaction = transaction;
command.ExecuteNonQuery();
// ...
transaction.Commit(); // 提交事务
}
catch (Exception)
{
transaction.Rollback(); // 回滚事务
}
}
EF Core的SaveChanges()或SaveChangesAsync()默认会在一个事务中执行所有更改。
技术选型对比
| 特性 | ADO.NET | Entity Framework Core | Dapper |
|---|---|---|---|
| 性能 | 最高 | 较高(略低于ADO.NET) | 非常高,接近原生ADO.NET |
| 易用性 | 较低,代码繁琐 | 非常高,开发效率高 | 中等,需手写SQL |
| 控制力 | 完全控制SQL | 抽象化,控制力较低 | 完全控制SQL |
| 学习曲线 | 陡峭 | 平缓 | 中等 |
| 适用场景 | 性能敏感、复杂SQL、底层框架 | 快速开发、业务逻辑复杂、CRUD操作多 | 需要高性能且希望手写SQL的场景 |
相关问答 (FAQs)
问题1:作为初学者,我应该选择ADO.NET还是Entity Framework Core?
解答: 这取决于你的项目需求和学习目标。
- 选择Entity Framework Core:如果你希望快速开发,专注于业务逻辑而不是数据库细节,并且你的项目以标准的CRUD(创建、读取、更新、删除)操作为主,那么EF Core是绝佳选择,它大大提高了开发效率,代码更易维护。
- 选择ADO.NET:如果你想深入理解.NET与数据库交互的底层原理,或者你的项目对性能有极致要求,需要执行高度复杂的SQL查询或存储过程,那么从ADO.NET开始学习会非常有价值,掌握ADO.NET能让你在遇到EF Core无法解决的性能问题时,有能力进行底层优化。
问题2:ExecuteNonQuery, ExecuteScalar, 和 ExecuteReader 有什么区别?
解答: 这三个都是SqlCommand对象用于执行SQL命令的方法,但用途和返回值不同。
ExecuteNonQuery():用于执行不返回结果集的命令,如INSERT,UPDATE,DELETE或DDL语句,它返回一个整数,表示受影响的行数,这是进行数据录入、更新和删除时的标准方法。ExecuteScalar():用于执行只返回单个值(如第一行第一列)的查询,查询SELECT COUNT(*) FROM Users或SELECT Name FROM Users WHERE Id = 1,它返回一个object类型,需要你进行类型转换。ExecuteReader():用于执行返回多行多列结果集的查询,如SELECT * FROM Users,它返回一个SqlDataReader对象,你可以通过这个对象向前遍历查询结果,它适用于需要读取大量数据的场景。