当前位置:首页 > 虚拟主机 > 正文

C程序设计数据库怎么连接?C操作SQL Server数据库教程

在C#程序设计中,数据库交互是构建企业级应用、Web服务及桌面软件的核心环节,C#通过ADO.NET框架提供了强大的数据访问能力,并结合Entity Framework等ORM(对象关系映射)工具,极大地简化了数据库操作,以下将详细阐述C#连接数据库的基础原理、常用技术栈、代码实现模式以及最佳实践。

核心数据访问技术栈

C#访问数据库主要依赖以下几种技术,它们各有侧重,适用于不同的场景:

技术名称 类型 特点描述 适用场景
ADO.NET 底层API 微软官方提供的原生数据访问接口,包含SqlConnection, SqlCommand等类,性能极高,控制力强。 高性能要求、需要精细控制SQL执行、遗留系统维护。
Entity Framework (EF) ORM框架 将数据库表映射为C#类,支持LINQ查询,自动生成SQL,分为EF6(传统)和EF Core(跨平台、轻量)。 快速开发、复杂业务逻辑、需要减少样板代码的项目。
Dapper 微ORM 轻量级ORM,基于ADO.NET封装,性能接近原生ADO.NET,支持动态对象映射。 对性能敏感但希望保留部分ORM便利性的场景。
SQLClient 驱动库 通常指System.Data.SqlClient或新的Microsoft.Data.SqlClient,是连接SQL Server的具体驱动程序。 所有基于SQL Server的数据访问基础。

基于ADO.NET的基础连接与查询

使用ADO.NET进行数据库操作通常遵循“连接-命令-执行-关闭”的生命周期,为了确保资源正确释放,推荐使用using语句块。

建立数据库连接

连接字符串是访问数据库的凭证,通常存储在配置文件(如appsettings.json或

web.config)中,而非硬编码在代码里。

C程序设计数据库怎么连接?C操作SQL Server数据库教程 第1张

执行查询并读取数据

当需要获取数据时,使用SqlCommand执行SQL语句,并通过SqlDataReader逐行读取结果,这种方式内存占用低,适合读取大量数据。

public List<string> GetProductNames() { var productNames = new List<string>(); string query = "SELECT Name FROM Products WHERE IsActive = 1"; using (var connection = new SqlConnection(_connectionString)) using (var command = new SqlCommand(query, connection)) { connection.Open(); // ExecuteReader 返回一个只进只读的流式数据读取器 using (var reader = command.ExecuteReader()) { while (reader.Read()) { // 通过列名或索引获取值 productNames.Add(reader.GetString(0)); } } } return productNames; }

执行插入、更新和删除操作

对于非查询操作,使用ExecuteNonQuery方法,该方法返回受影响的行数,为了防止SQL载入攻破,必须使用参数化查询。

public int AddProduct(string name, decimal price) { string query = "INSERT INTO Products (Name, Price, IsActive) VALUES (@Name, @Price, 1)"; using (var connection = new SqlConnection(_connectionString)) using (var command = new SqlCommand(query, connection)) { // 添加参数,防止SQL载入 command.Parameters.AddWithValue("@Name", name); command.Parameters.AddWithValue("@Price", price); connection.Open(); // 返回受影响的行数 return command.ExecuteNonQuery(); } }

Entity Framework Core (EF Core) 的现代开发模式

EF Core是目前C#开发中最流行的ORM框架,它允许开发者使用C#代码而非SQL来操作数据库。

定义实体模型

C程序设计数据库怎么连接?C操作SQL Server数据库教程 第2张

首先定义与数据库表对应的C#类。

public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } public bool IsActive { get; set; } }

配置上下文

DbContext是EF Core的核心,负责管理数据库连接和实体对象的状态。

using Microsoft.EntityFrameworkCore; public class AppDbContext : DbContext { public DbSet<Product> Products { get; set; } public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } // 可选:配置实体映射细节 protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Product>() .ToTable("Products") .HasKey(p => p.Id); } }

执行CRUD操作

EF Core支持LINQ,使得查询非常直观。

public class ProductService { private readonly AppDbContext _context; public ProductService(AppDbContext context) { _context = context; } // 查询 public List<Product> GetActiveProducts() { return _context.Products .Where(p => p.IsActive) .ToList(); } // 添加 public void AddProduct(Product product) { _context.Products.Add(product); _context.SaveChanges(); // 提交更改到数据库 } // 更新 public void UpdateProductPrice(int id, decimal newPrice) { var product = _context.Products.Find(id); if (product != null) { product.Price = newPrice; _context.SaveChanges(); } } }

关键最佳实践与安全建议

  1. 防止SQL载入:永远不要使用字符串拼接来构建SQL语句,始终使用参数化查询(ADO.NET)或ORM框架提供的查询方法(EF Core)。
  2. 连接管理:ADO.NET的连接池机制非常高效,但务必确保连接在使用后正确关闭。using语句是最佳实践。
  3. 异步编程:在现代C#应用中,推荐使用异步方法(async/await)以避免阻塞线程,提高应用程序的可扩展性,使用ExecuteReaderAsync或ToListAsync。
  4. 依赖载入:在ASP.NET Core等现代框架中,将DbContext或数据库服务注册为依赖载入容器的一部分,便于测试和维护。
  5. 异常处理:数据库操作可能因网络、权限或数据约束失败,应捕获SqlException或DbUpdateException并进行适当的日志记录和用户提示。

相关问题与解答

问题1:在C#中,ADO.NET的SqlDataReader和Entity Framework的ToList()方法在性能和使用场景上有何主要区别?

解答:

SqlDataReader是ADO.NET中用于读取数据流的方式,它是“只进只读”的,意味着数据一旦读取过就不能回头,且它不会将数据缓存到内存中,而是直接从数据库流式传输,在处理海量数据(如百万级记录)时,SqlDataReader内存占用极低,性能最高,适合报表生成或大数据导出。

相比之下,ToList()是LINQ to Entities的方法,它会将查询结果全部加载到内存中,构建完整的实体对象列表,这种方式方便进行后续的数据操作(如排序、过滤、导航属性访问),但会消耗较多内存,如果数据量极大,可能导致内存溢出(OOM),小数据量或需要复杂对象操作时使用ToList(),大数据量或仅需遍历读取时使用SqlDataReader。

问题2:为什么在使用Entity Framework Core时,SaveChanges()方法有时会被认为是性能瓶颈,如何优化?

解答:

SaveChanges()方法会将当前DbContext中所有标记为“新增”、“修改”或“删除”的实体一次性提交到数据库,如果在一个循环中频繁调用SaveChanges(),或者一次性提交成千上万条记录,会导致大量的数据库事务开销和网络往返,从而成为性能瓶颈。

优化策略包括:

  1. 批量提交:将需要保存的数据收集起来,一次性调用SaveChanges(),而不是在循环内部调用。
  2. 使用批量插入库:对于超大规模数据插入(如数万条以上),可以使用第三方库如EFCore.BulkExtensions,它通过SQL批量插入命令(Bulk Insert)绕过EF Core的单条记录跟踪机制,性能可提升数十倍。
  3. 禁用变更追踪:如果只需要执行插入或更新操作而不需要读取实体状态,可以在查询时禁用变更追踪(AsNoTracking()),或在插入前不附加到上下文,以减少EF Core跟踪对象状态的计算开销。

C程序设计数据库怎么连接?C操作SQL Server数据库教程 第3张

0