C# 数据库访问与ORM框架全面指南:从ADO.NET到Entity Framework Core

在现代应用开发中,数据持久化是核心需求之一。作为.NET生态系统中的主力语言,C#提供了丰富多样的数据库访问技术和工具。本文将全面探讨C#中的数据库访问方式,重点介绍三种主流ORM(对象关系映射)框架:Entity Framework Core、Dapper和NHibernate,帮助开发者根据项目需求做出合理的技术选型。

第一部分:基础数据库访问 - ADO.NET

1.1 ADO.NET架构概述

ADO.NET是.NET平台数据访问的基石,提供了一套面向连接的、断开式的数据访问模型。其主要组件包括:

  • Connection:建立与数据库的连接

  • Command:执行SQL命令

  • DataReader:高效的前向只读数据流

  • DataAdapter:在数据源和DataSet之间架桥

  • DataSet:内存中的数据库表示

1.2 典型使用模式

// 连接字符串示例
string connStr = "Server=.;Database=Northwind;Integrated Security=True;";using (SqlConnection conn = new SqlConnection(connStr))
{// 打开连接conn.Open();// 执行查询string sql = "SELECT ProductID, ProductName FROM Products WHERE CategoryID = @CategoryID";using (SqlCommand cmd = new SqlCommand(sql, conn)){cmd.Parameters.AddWithValue("@CategoryID", 1);using (SqlDataReader reader = cmd.ExecuteReader()){while (reader.Read()){Console.WriteLine($"{reader["ProductID"]}: {reader["ProductName"]}");}}}// 执行插入string insertSql = "INSERT INTO Products (ProductName, CategoryID) VALUES (@Name, @CatID)";using (SqlCommand cmd = new SqlCommand(insertSql, conn)){cmd.Parameters.AddWithValue("@Name", "New Product");cmd.Parameters.AddWithValue("@CatID", 1);int rowsAffected = cmd.ExecuteNonQuery();Console.WriteLine($"插入了 {rowsAffected} 行");}
}

1.3 ADO.NET优缺点分析

优点

  • 最接近数据库底层的访问方式

  • 性能最佳

  • 完全控制SQL语句

  • 适合复杂查询和存储过程调用

缺点

  • 需要手动编写大量样板代码

  • 容易产生SQL注入漏洞

  • 对象关系映射需要手动实现

  • 维护成本高

第二部分:现代ORM框架

2.1 Entity Framework Core

2.1.1 EF Core概述

Entity Framework Core是微软官方推出的ORM框架,是.NET生态中最流行的数据访问解决方案。

2.1.2 核心概念

  • DbContext:数据库会话,工作单元模式的实现

  • DbSet:实体集合,对应数据库表

  • 迁移(Migrations):代码优先的数据库架构管理

  • LINQ提供程序:将LINQ转换为SQL

2.1.3 完整示例

// 定义实体
public class Blog
{public int BlogId { get; set; }public string Url { get; set; }public int Rating { get; set; }public List<Post> Posts { get; set; }
}public class Post
{public int PostId { get; set; }public string Title { get; set; }public string Content { get; set; }public int BlogId { get; set; }public Blog Blog { get; set; }
}// 定义DbContext
public class BloggingContext : DbContext
{public DbSet<Blog> Blogs { get; set; }public DbSet<Post> Posts { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer("Server=.;Database=BloggingDemo;Trusted_Connection=True;");
}// 使用示例
using (var db = new BloggingContext())
{// 创建var blog = new Blog { Url = "http://example.com", Rating = 5 };db.Blogs.Add(blog);db.SaveChanges();// 查询var topBlogs = db.Blogs.Where(b => b.Rating > 3).OrderByDescending(b => b.Rating).ToList();// 更新var firstBlog = db.Blogs.First();firstBlog.Url = "http://updated.com";db.SaveChanges();// 删除var lastBlog = db.Blogs.OrderBy(b => b.BlogId).Last();db.Blogs.Remove(lastBlog);db.SaveChanges();
}

2.1.4 EF Core高级特性

  • 延迟加载virtual导航属性+代理

  • 预先加载Include/ThenInclude

  • 显式加载Entry(...).Collection(...).Load()

  • 全局查询过滤器modelBuilder.Entity<T>().HasQueryFilter(...)

  • 影子属性:模型中未定义的列

  • 值转换器:自定义类型映射

2.2 Dapper

2.2.1 Dapper概述

Dapper是Stack Overflow开发的高性能微型ORM,在ADO.NET基础上提供了简单的对象映射功能。

2.2.2 核心特点

  • 轻量级(单个文件)

  • 几乎零学习成本

  • 性能接近原生ADO.NET

  • 支持多映射和存储过程

2.2.3 完整示例

using Dapper;
using System.Data.SqlClient;// 基本查询
string connectionString = "Server=.;Database=Northwind;Integrated Security=True;";using (var connection = new SqlConnection(connectionString))
{var products = connection.Query<Product>("SELECT * FROM Products WHERE CategoryID = @CatID",new { CatID = 1 });foreach (var product in products){Console.WriteLine(product.ProductName);}
}// 多映射示例
var sql = @"SELECT p.*, c.* FROM Products p INNER JOIN Categories c ON p.CategoryID = c.CategoryIDWHERE p.ProductID = @Id";using (var connection = new SqlConnection(connectionString))
{var product = connection.Query<Product, Category, Product>(sql,(prod, cat) => { prod.Category = cat; return prod; },new { Id = 1 },splitOn: "CategoryID").FirstOrDefault();Console.WriteLine($"{product.ProductName} 属于 {product.Category.CategoryName}");
}// 执行存储过程
using (var connection = new SqlConnection(connectionString))
{var parameters = new DynamicParameters();parameters.Add("@CategoryID", 1);parameters.Add("@ProductCount", dbType: DbType.Int32, direction: ParameterDirection.Output);var products = connection.Query<Product>("CustOrderHist",parameters,commandType: CommandType.StoredProcedure);int productCount = parameters.Get<int>("@ProductCount");
}

2.3 NHibernate

2.3.1 NHibernate概述

NHibernate是.NET平台上的成熟ORM框架,移植自Java的Hibernate,功能全面但配置复杂。

2.3.2 核心概念

  • SessionFactory:线程安全,应用生命周期单例

  • Session:工作单元,非线程安全

  • 映射文件:.hbm.xml或Fluent配置

  • HQL:Hibernate查询语言

  • Criteria API:类型安全的查询构建

2.3.3 完整示例

<!-- Product.hbm.xml -->
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"><class name="Product" table="Products"><id name="Id" column="ProductID"><generator class="identity" /></id><property name="Name" column="ProductName" /><property name="Price" /><many-to-one name="Category" column="CategoryID" /></class>
</hibernate-mapping>
// 配置和用法
var cfg = new Configuration();
cfg.Configure(); // 读取hibernate.cfg.xml
cfg.AddAssembly(typeof(Product).Assembly);var sessionFactory = cfg.BuildSessionFactory();using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{// 保存var newProduct = new Product { Name = "New Product", Price = 9.99m,Category = session.Load<Category>(1)};session.Save(newProduct);// 查询var products = session.CreateCriteria<Product>().Add(Restrictions.Like("Name", "N%")).List<Product>();// HQL查询var hqlProducts = session.CreateQuery("FROM Product WHERE Price > :price").SetDecimal("price", 5m).List<Product>();tx.Commit();
}

第三部分:技术选型指南

3.1 比较矩阵

特性ADO.NETDapperEF CoreNHibernate
学习曲线
性能最高
开发速度
功能丰富度最高
LINQ支持有限完整部分
迁移工具
社区支持最高

3.2 推荐场景

选择ADO.NET当

  • 需要极致性能

  • 项目简单,表结构稳定

  • 需要完全控制SQL

  • 使用复杂存储过程

选择Dapper当

  • 需要接近原生性能

  • 项目使用微服务架构

  • 已有良好设计的SQL

  • 需要轻量级解决方案

选择EF Core当

  • 开发速度是关键因素

  • 使用代码优先开发

  • 需要LINQ支持

  • 项目中等复杂度

选择NHibernate当

  • 需要最丰富的ORM功能

  • 项目非常复杂

  • 需要二级缓存等高级特性

  • 团队有Hibernate经验

第四部分:最佳实践与性能优化

4.1 通用最佳实践

  1. 连接管理:始终确保连接被正确关闭(使用using语句)

  2. 参数化查询:永远使用参数防止SQL注入

  3. 错误处理:实现适当的重试机制

  4. 日志记录:记录关键数据库操作

  5. 分页处理:大数据集必须分页

4.2 EF Core特定优化

  1. 批量操作

    // 不好的做法
    foreach (var item in items)
    {context.Add(item);context.SaveChanges(); // 每次保存
    }// 好的做法
    context.AddRange(items);
    context.SaveChanges(); // 批量保存
  2. 选择合适的数据加载方式

    // 预先加载(查询时)
    var blogs = context.Blogs.Include(b => b.Posts).ToList();// 显式加载(需要时)
    var blog = context.Blogs.First();
    context.Entry(blog).Collection(b => b.Posts).Load();// 延迟加载(访问时,需配置)
    public class Blog
    {public virtual ICollection<Post> Posts { get; set; }
    }
  3. 禁用跟踪

    var blogs = context.Blogs.AsNoTracking() // 只读操作使用.ToList();
  4. 使用原始SQL优化复杂查询

    var blogs = context.Blogs.FromSqlRaw("SELECT * FROM Blogs WHERE Rating > {0}", 3).ToList();

4.3 Dapper优化技巧

  1. 使用多映射减少查询次数

    var sql = @"SELECT * FROM Orders o INNER JOIN Customers c ON o.CustomerID = c.CustomerIDWHERE o.OrderDate > @Date";var orders = connection.Query<Order, Customer, Order>(sql,(order, customer) => { order.Customer = customer; return order; },new { Date = DateTime.Now.AddDays(-30) },splitOn: "CustomerID");
  2. 批量插入

    var sql = "INSERT INTO Products (Name, Price) VALUES (@Name, @Price)";
    connection.Execute(sql, products); // products是对象列表

结语

C#生态系统提供了从底层到高层的完整数据库访问解决方案。对于大多数应用场景,Entity Framework Core提供了最佳的生产力和功能平衡;对性能敏感的场景,Dapper是不二之选;而复杂的企业级应用可能会从NHibernate的丰富功能中受益。无论选择哪种技术,理解底层原理和遵循最佳实践都是构建高效、可维护数据访问层的关键。

希望这篇全面指南能帮助您在C#项目中做出明智的数据库访问技术决策。根据项目需求、团队技能和性能要求选择最适合的工具,并记住:没有放之四海而皆准的解决方案,只有最适合特定场景的选择。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/diannao/85688.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

day19 leetcode-hot100-37(二叉树2)

104. 二叉树的最大深度 - 力扣&#xff08;LeetCode&#xff09; 1.深度优先遍历&#xff08;递归&#xff09;ps:不好理解&#xff0c;所以我一般不喜欢用递归 思路 典型算法&#xff0c;用递归求出高度&#xff0c;每次都是深度优先。 具体算法 /*** Definition for a bi…

【LLMs篇】13:LLaDA—大型语言扩散模型

栏目内容论文标题大型语言扩散模型 (Large Language Diffusion Models)核心思想提出LLaDA&#xff0c;一种基于扩散模型的LLM&#xff0c;通过前向掩码和反向预测过程建模语言分布&#xff0c;挑战自回归模型&#xff08;ARM&#xff09;在LLM领域的主导地位&#xff0c;并展示…

Deepfashion2 数据集使用笔记

目录 数据类别: 筛选类别数据: 验证筛选前2个类别: Deepfashion2 的解压码 数据类别: 类别含义: Class idx类别名称英文名称0短上衣short sleeve top1长上衣long sleeve top2短外套short sleeve outwear3长外套long sleeve outwear4裙子skirt5裤子trousers6连衣裙dre…

Java并发编程哲学系列汇总

文章目录 并发编程基础并发编程进阶并发编程实践 并发编程基础 Java并发编程基础小结 Java线程池知识点小结 详解JUC包下各种锁的使用 并发编程利器Java CAS原子类全解 深入理解Java中的final关键字 Java并发容器深入解析&#xff1a;HashMap与ArrayList线程安全问题及解…

git 之 stash

一、git stash&#xff1a;临时保存工作区修改 作用 将当前工作目录和暂存区的未提交修改保存到栈中&#xff0c;并恢复工作区到上一次提交的干净状态。 适用场景&#xff1a; 临时切换分支修复紧急 Bug拉取远程代码前清理工作区保存实验性代码避免生成无效提交 常用命令&am…

vxe-grid 双击行,打开expand的内容

1、官网api Vxe Table v4.6&#xff08;根据版本&#xff09; 要调用这个事件&#xff0c;双击单元格&#xff0c;我们打开type"expand"的内容 2、打开的事件toggleRowExpand 3、事件的说明 这个方法&#xff0c;会自动判断当前展开的状态&#xff0c;然后去触发相…

Java Stream 高级实战:并行流、自定义收集器与性能优化

一、并行流深度实战&#xff1a;大规模数据处理的性能突破 1.1 并行流的核心应用场景 在电商用户行为分析场景中&#xff0c;需要对百万级用户日志数据进行实时统计。例如&#xff0c;计算某时段内活跃用户数&#xff08;访问次数≥3次的用户&#xff09;&#xff0c;传统循环…

计算机系统结构-第5章-监听式协议

监听式协议******&#xff1a; 思想: 每个Cache除了包含物理存储器中块的数据拷贝之外&#xff0c;也保存着各个块的共享状态信息。 Cache通常连在共享存储器的总线上&#xff0c;当某个Cache需要访问存储器时&#xff0c;它会把请求放到总线上广播出去&#xff0c;其他各个C…

(c++)string的模拟实现

目录 1.构造函数 2.析构函数 3.扩容 1.reserve(扩容不初始化) 2.resize(扩容加初始化) 4.push_back 5.append 6. 运算符重载 1.一个字符 2.一个字符串 7 []运算符重载 8.find 1.找一个字符 2.找一个字符串 9.insert 1.插入一个字符 2.插入一个字符串 9.erase 10…

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2]

学习笔记(24): 机器学习之数据预处理Pandas和转换成张量格式[2] 学习机器学习&#xff0c;需要学习如何预处理原始数据&#xff0c;这里用到pandas&#xff0c;将原始数据转换为张量格式的数据。 学习笔记(23): 机器学习之数据预处理Pandas和转换成张量格式[1]-CSDN博客 下面…

LeetCode 2297. 跳跃游戏 VIII(中等)

题目描述 给定一个长度为 n 的下标从 0 开始的整数数组 nums。初始位置为下标 0。当 i < j 时&#xff0c;你可以从下标 i 跳转到下标 j: 对于在 i < k < j 范围内的所有下标 k 有 nums[i] < nums[j] 和 nums[k] < nums[i] , 或者对于在 i < k < j 范围…

【前端】缓存相关

本知识页参考&#xff1a;https://zhuanlan.zhihu.com/p/586060532 1. 概述 1.1 应用场景 静态资源 场景&#xff1a;图片、CSS、JS 文件等静态资源实现&#xff1a;使用 HTTP 缓存控制头&#xff0c;或者利用 CDN 进行边缘缓存 数据缓存 场景&#xff1a;请求的返回结果实现…

猎板硬金镀层厚度:高频通信领域的性能分水岭

在 5G 基站、毫米波雷达等高频场景中&#xff0c;硬金镀层厚度的选择直接决定了 PCB 的信号完整性与长期可靠性。猎板硬金工艺&#xff1a; 1.8μm 金层搭配罗杰斯 4350B 基材的解决方案&#xff0c;在 10GHz 频段实现插入损耗&#xff1c;0.15dB/cm&#xff0c;较常规工艺降低…

第35次CCF计算机软件能力认证-5-木板切割

原题链接&#xff1a; TUOJ 我自己写的35分正确但严重超时的代码 #include <bits/stdc.h> using namespace std; int main() {int n, m, k;cin >> n >> m >> k;vector<unordered_map<int, int>> mp(2);int y;for (int i 1; i < n; …

【蓝桥杯】包子凑数

包子凑数 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 NN 种蒸笼&#xff0c;其中第 ii 种蒸笼恰好能放 AiAi​ 个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 XX 个包子&#xff0c;卖包子的大叔就会迅速选出若干…

pikachu通关教程-目录遍历漏洞(../../)

目录遍历漏洞也可以叫做信息泄露漏洞、非授权文件包含漏洞等. 原理:目录遍历漏洞的原理比较简单&#xff0c;就是程序在实现上没有充分过滤用户输入的../之类的目录跳转符&#xff0c;导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件。 这里的目录跳转符可以是../…

[概率论基本概念4]什么是无偏估计

关键词&#xff1a;Unbiased Estimation 一、说明 对于无偏和有偏估计&#xff0c;需要了解其叙事背景&#xff0c;是指整体和抽样的关系&#xff0c;也就是说整体的叙事是从理论角度的&#xff0c;而估计器原理是从实践角度说事&#xff1b;为了表明概率理论&#xff08;不可…

面试题——计算机网络:HTTP和HTTPS的区别?

HTTP&#xff08;HyperText Transfer Protocol&#xff09;&#xff1a;作为互联网上应用最广泛的网络通信协议&#xff0c;HTTP是基于TCP/IP协议族的应用层协议。它采用标准的请求-响应模式进行通信&#xff0c;通过简洁的报文格式&#xff08;包含请求行、请求头、请求体等&a…

uni-app学习笔记十九--pages.json全局样式globalStyle设置

pages.json 页面路由 pages.json 文件用来对 uni-app 进行全局配置&#xff0c;决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。 导航栏高度为 44px (不含状态栏)&#xff0c;tabBar 高度为 50px (不含安全区)。 它类似微信小程序中app.json的页面管理部…

SQL思路解析:窗口滑动的应用

目录 &#x1f3af; 问题目标 第一步&#xff1a;从数据中我们能直接得到什么&#xff1f; 第二步&#xff1a;我们想要的“7天窗口”长什么样&#xff1f; 第三步&#xff1a;SQL 怎么表达“某一天的前六天”&#xff1f; &#x1f50d;JOIN 比窗口函数更灵活 第四步&am…