.NET Core ORM框架用法簡述
一、主流.NET Core ORM框架概述
在.NET Core生態系統中,主流的ORM(Object-Relational Mapping)框架包括:
- ??Entity Framework Core (EF Core)?? - 微軟官方推出的ORM框架
- ??Dapper?? - 輕量級微ORM
- ??Npgsql.EntityFrameworkCore.PostgreSQL?? - PostgreSQL專用EF Core提供程序
- ??Pomelo.EntityFrameworkCore.MySql?? - MySQL專用EF Core提供程序
- ??LINQ to DB?? - 高性能ORM
本文重點介紹最常用的EF Core和Dapper。
二、Entity Framework Core (EF Core) 使用指南
1. 安裝與配置
??安裝NuGet包??:
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer # SQL Server提供程序
# 或其他數據庫提供程序
??DbContext配置??:
public class AppDbContext : DbContext
{public DbSet<User> Users { get; set; }public DbSet<Order> Orders { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer("Server=.;Database=MyApp;Trusted_Connection=True;");}
}
??依賴注入配置??(推薦):
// Startup.cs或Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
2. 數據模型定義
??實體類??:
public class User
{public int Id { get; set; }public string Name { get; set; }public DateTime BirthDate { get; set; }// 導航屬性public ICollection<Order> Orders { get; set; }
}public class Order
{public int Id { get; set; }public decimal Amount { get; set; }public DateTime OrderDate { get; set; }// 外鍵和導航屬性public int UserId { get; set; }public User User { get; set; }
}
??Fluent API配置??:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<User>().Property(u => u.Name).IsRequired().HasMaxLength(50);modelBuilder.Entity<Order>().HasOne(o => o.User).WithMany(u => u.Orders).HasForeignKey(o => o.UserId);
}
3. CRUD操作
??添加數據??:
using (var context = new AppDbContext())
{var user = new User { Name = "張三", BirthDate = new DateTime(1990, 1, 1) };context.Users.Add(user);context.SaveChanges();
}
??查詢數據??:
// 簡單查詢
var users = context.Users.ToList();// 條件查詢
var activeUsers = context.Users.Where(u => u.Name.Contains("張")).OrderBy(u => u.BirthDate).ToList();// 投影查詢
var userNames = context.Users.Select(u => new { u.Id, u.Name }).ToList();
??更新數據??:
using (var context = new AppDbContext())
{var user = context.Users.Find(1);if (user != null){user.Name = "李四";context.SaveChanges();}
}
??刪除數據??:
using (var context = new AppDbContext())
{var user = context.Users.Find(1);if (user != null){context.Users.Remove(user);context.SaveChanges();}
}
4. 高級功能
??異步操作??:
var user = await context.Users.FindAsync(1);
var users = await context.Users.Where(u => u.Name.Contains("張")).ToListAsync();
??事務處理??:
using (var transaction = await context.Database.BeginTransactionAsync())
{try{// 執行多個操作await context.SaveChangesAsync();await transaction.CommitAsync();}catch{await transaction.RollbackAsync();throw;}
}
??遷移管理??:
# 添加遷移
dotnet ef migrations add InitialCreate# 更新數據庫
dotnet ef database update# 回滾遷移
dotnet ef database update PreviousMigration
三、Dapper使用指南
1. 安裝與配置
??安裝NuGet包??:
dotnet add package Dapper
dotnet add package System.Data.SqlClient # SQL Server提供程序
??基本使用??:
using var connection = new SqlConnection("Server=.;Database=MyApp;Trusted_Connection=True;");
connection.Open();
2. CRUD操作
??查詢數據??:
var users = connection.Query<User>("SELECT * FROM Users WHERE Name LIKE @Name", new { Name = "%張%" });var user = connection.QueryFirstOrDefault<User>("SELECT * FROM Users WHERE Id = @Id", new { Id = 1 });
??插入數據??:
var id = connection.QuerySingle<int>("INSERT INTO Users (Name, BirthDate) VALUES (@Name, @BirthDate); SELECT SCOPE_IDENTITY();",new { Name = "張三", BirthDate = DateTime.Now });
??更新數據??:
var affectedRows = connection.Execute("UPDATE Users SET Name = @Name WHERE Id = @Id",new { Name = "李四", Id = 1 });
??刪除數據??:
var deletedRows = connection.Execute("DELETE FROM Users WHERE Id = @Id", new { Id = 1 });
3. 高級功能
??存儲過程調用??:
var users = connection.Query<User>("dbo.GetUsersByAgeRange", new { MinAge = 18, MaxAge = 30 },commandType: CommandType.StoredProcedure);
??多結果集處理??:
using (var multi = connection.QueryMultiple("SELECT * FROM Users; SELECT * FROM Orders", commandType: CommandType.Text))
{var users = multi.Read<User>().ToList();var orders = multi.Read<Order>().ToList();
}
??動態參數??:
var sql = "SELECT * FROM Users WHERE 1=1";
var parameters = new DynamicParameters();
if (!string.IsNullOrEmpty(name))
{sql += " AND Name = @Name";parameters.Add("Name", name);
}
if (minAge.HasValue)
{sql += " AND Age >= @MinAge";parameters.Add("MinAge", minAge.Value);
}var users = connection.Query<User>(sql, parameters);
四、EF Core與Dapper對比
特性 | EF Core | Dapper |
---|---|---|
??性能?? | 中等(有ORM開銷) | 高(接近原生SQL) |
??學習曲線?? | 較陡峭(需理解LINQ、EF概念) | 平緩(SQL知識即可) |
??功能豐富度?? | 高(遷移、跟蹤、變更檢測等) | 低(僅數據訪問) |
??適用場景?? | 復雜業務、快速開發 | 高性能需求、復雜SQL |
??異步支持?? | 原生支持 | 需手動實現 |
??事務管理?? | 內置支持 | 需手動實現 |
??緩存?? | 一級緩存 | 無內置緩存 |
五、選擇建議
-
??選擇EF Core當??:
- 需要快速開發CRUD應用
- 團隊熟悉ORM概念
- 需要數據庫遷移功能
- 項目需要頻繁變更數據模型
-
??選擇Dapper當??:
- 需要極致性能
- 執行復雜SQL查詢
- 已有成熟的SQL知識
- 項目以讀為主,寫操作較少
六、最佳實踐
EF Core最佳實踐
-
??合理使用延遲加載??:
// 禁用延遲加載(推薦) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {optionsBuilder.UseLazyLoadingProxies(false); }
-
??批量操作優化??:
// 使用AddRange代替多個Add context.Users.AddRange(usersList);// 對于大量數據,考慮分批處理 foreach (var batch in usersList.Batch(500)) {context.Users.AddRange(batch);context.SaveChanges(); }
-
??避免N+1查詢??:
// 不好的做法(會導致N+1) var users = context.Users.ToList(); foreach (var user in users) {var orders = context.Orders.Where(o => o.UserId == user.Id).ToList(); }// 好的做法(預加載) var users = context.Users.Include(u => u.Orders).ToList();
Dapper最佳實踐
-
??使用參數化查詢??:
// 安全的方式 connection.Query<User>("SELECT * FROM Users WHERE Name = @Name", new { Name = userInput });// 避免拼接SQL字符串(有SQL注入風險) // connection.Query<User>($"SELECT * FROM Users WHERE Name = '{userInput}'");
-
??連接管理??:
// 使用using確保連接釋放 using (var connection = new SqlConnection(connectionString)) {connection.Open();// 執行操作 }
-
??存儲過程調用??:
var result = connection.QueryFirstOrDefault<int>("dbo.GetUserCountByRole",new { RoleId = roleId },commandType: CommandType.StoredProcedure);
七、性能優化技巧
EF Core性能優化
-
??啟用查詢緩存??:
services.AddDbContext<AppDbContext>(options =>options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking).UseSqlServer(connectionString));
-
??使用AsNoTracking??:
// 只讀場景使用 var users = context.Users.AsNoTracking().ToList();
-
??投影查詢??:
// 只查詢需要的字段 var userDtos = context.Users.Select(u => new UserDto { Id = u.Id, Name = u.Name }).ToList();
Dapper性能優化
-
??使用ExecuteScalar代替QueryFirstOrDefault??:
// 獲取單個值 var count = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM Users");
-
??使用動態類型??:
// 當不需要強類型時 var result = connection.Query("SELECT * FROM Users").FirstOrDefault();
-
??連接池配置??:
// 在連接字符串中配置 "Server=.;Database=MyApp;User Id=user;Password=pass;Max Pool Size=100;"
八、常見問題解決
EF Core常見問題
-
??N+1查詢問題??:
- 使用
Include
或ThenInclude
預加載 - 使用
Select
投影查詢
- 使用
-
??性能下降??:
- 檢查生成的SQL(使用日志)
- 考慮禁用變更跟蹤(
AsNoTracking
) - 優化數據庫索引
-
??遷移沖突??:
- 使用
dotnet ef migrations remove
回滾 - 手動合并遷移文件
- 使用
Dapper常見問題
-
??SQL注入風險??:
- 始終使用參數化查詢
- 避免字符串拼接SQL
-
??連接泄漏??:
- 確保使用
using
語句 - 實現IDisposable模式管理連接
- 確保使用
-
??結果映射錯誤??:
- 檢查列名與屬性名匹配
- 使用
Query<T>
時確保T有默認構造函數
九、工具與擴展
EF Core工具
-
??EF Core Power Tools??:
- 可視化查看數據庫模型
- 快速生成實體類
- 執行數據庫比較
-
??Entity Framework Core Profiler??:
- 分析EF Core生成的SQL
- 性能監控
Dapper擴展
-
??Dapper.Contrib??:
- 添加簡單的CRUD擴展方法
connection.Insert(user); connection.Update(user);
-
??Dapper.FluentMap??:
- 配置實體到表的映射
FluentMapper.Initialize(config => {config.AddMap(new UserMap()); });
-
??DapperQueryBuilder??:
- 構建安全動態SQL
var query = connection.QueryBuilder($"SELECT * FROM Users WHERE 1=1"); if (name != null) query.Where("Name = @Name", new { Name = name }); var users = query.Query<User>();
十、總結與建議
-
??EF Core適合??:
- 快速開發的企業應用
- 需要數據庫遷移的項目
- 團隊熟悉ORM的情況
-
??Dapper適合??:
- 高性能要求的微服務
- 復雜SQL查詢場景
- 已有成熟SQL知識的項目
-
??混合使用策略??:
- 主框架使用EF Core
- 性能關鍵部分使用Dapper
// 在EF Core項目中使用Dapper public class UserRepository : IUserRepository {private readonly AppDbContext _context;private readonly IDbConnection _dapperConnection;public UserRepository(AppDbContext context, IDbConnection dapperConnection){_context = context;_dapperConnection = dapperConnection;}public User GetById(int id){// 使用EF Corereturn _context.Users.Find(id);}public IEnumerable<User> GetActiveUsers(){// 使用Dapper執行復雜查詢return _dapperConnection.Query<User>("SELECT * FROM Users WHERE IsActive = 1");} }
通過合理選擇ORM框架并遵循最佳實踐,可以顯著提高.NET Core應用程序的開發效率和性能表現。