- EF Core核心架构:从DbContext到LINQ查询的底层实现
- 三种开发模式:Database First/Code First/Model First实战
- 性能优化:延迟加载、分页查询、NoTracking技巧
- 分布式事务:跨数据库事务的实现与异常处理
- 多数据库支持:SQL Server/MySQL/PostgreSQL无缝切换
一、EF Core核心架构与DbContext
1.1 DbContext的底层魔法
/// <summary>
/// 博客系统数据库上下文
/// </summary>
public class BloggingContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 配置多数据库支持
optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=Blogging;Trusted_Connection=True;");
// optionsBuilder.UseMySql("Server=localhost;Database=Blogging;User=root;Password=123456;",
// new MySqlServerVersion(new Version(8, 0, 21)));
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置主键策略
modelBuilder.Entity<Post>()
.Property(p => p.PostId)
.ValueGeneratedOnAdd();
// 配置关系映射
modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(p => p.BlogId);
}
}
1.2 EF Core的生命周期管理
/// <summary>
/// 依赖注入式DbContext管理
/// </summary>
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// 使用设计时上下文工厂
services.AddDbContext<BloggingContext>(
options => options.UseSqlServer(Configuration.GetConnectionString("Default")));
// 注册分布式事务
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = Configuration.GetConnectionString("Default");
});
}
}
二、EF Core开发模式实战
2.1 Database First模式
步骤1:逆向工程生成模型
dotnet ef dbcontext scaffold "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer --context BloggingContext
步骤2:自动生成的实体类
[Table("Blogs")]
public partial class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
[InverseProperty("Blog")]
public virtual ICollection<Post> Posts { get; set; }
}
2.2 Code First模式
步骤1:定义实体类
/// <summary>
/// 博客实体(含自定义映射)
/// </summary>
public class Blog
{
[Key]
public int BlogId { get; set; }
[Required, MaxLength(255)]
public string Url { get; set; }
[ForeignKey("User")]
public int OwnerId { get; set; }
public virtual User Owner { get; set; }
}
步骤2:迁移与更新数据库
dotnet ef migrations add InitialCreate
dotnet ef database update
2.3 Model First模式(EF6特性)
// 通过EDMX文件设计模型
// 右键生成SQL脚本后执行
public partial class BlogModel : DbContext
{
public BlogModel() : base("name=BlogModel") { }
public virtual DbSet<Blog> Blogs { get; set; }
}
三、高级查询与性能优化
3.1 LINQ查询的黑科技
public class BlogService
{
private readonly BloggingContext _context;
public BlogService(BloggingContext context)
{
_context = context;
}
// 使用投影查询减少数据传输
public IEnumerable<PostSummary> GetPostSummaries()
{
return _context.Posts
.Where(p => p.Published)
.Select(p => new PostSummary
{
Id = p.PostId,
Title = p.Title,
Author = p.Blog.Owner.Name, // 跨实体查询
Views = p.ViewCount
})
.ToList();
}
// 分页查询优化
public PagedList<Post> GetPosts(int pageNumber, int pageSize)
{
return new PagedList<Post>(
_context.Posts
.OrderByDescending(p => p.CreatedOn)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize),
pageNumber,
pageSize);
}
}
3.2 NoTracking与延迟加载
// 禁用变化跟踪(读取场景)
public List<Post> GetPopularPosts()
{
return _context.Posts
.AsNoTracking() // 关键优化点
.Where(p => p.Views > 1000)
.ToList();
}
// 显式加载(避免N+1查询)
public void LoadPostDetails(int postId)
{
var post = _context.Posts
.Include(p => p.Blog)
.ThenInclude(b => b.Owner)
.FirstOrDefault(p => p.PostId == postId);
// 显式加载评论
_context.Entry(post).Collection(p => p.Comments).Load();
}
四、分布式事务与复杂场景
4.1 跨数据库事务(使用TransactionScope)
public class OrderService
{
private readonly BloggingContext _blogContext;
private readonly SalesContext _salesContext;
public void PlaceOrder(int blogId, decimal amount)
{
using (var scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions { IsolationLevel = IsolationLevel.Serializable }))
{
try
{
// 更新博客积分
var blog = _blogContext.Blogs.Find(blogId);
blog.Credits += 100;
// 插入销售记录
_salesContext.Orders.Add(new Order { BlogId = blogId, Amount = amount });
_blogContext.SaveChanges();
_salesContext.SaveChanges();
scope.Complete();
}
catch (Exception ex)
{
// 事务自动回滚
throw new TransactionException("订单处理失败", ex);
}
}
}
}
4.2 数据库迁移的版本控制
// 在DbContext中配置迁移历史表
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasAnnotation(
"ProductVersion",
"7.0.0"); // 强制指定EF版本
}
// 自定义迁移脚本
public partial class AddAuditColumns : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "CreatedAt",
table: "Posts",
type: "datetime2",
nullable: false,
defaultValueSql: "GETDATE()");
migrationBuilder.CreateIndex(
name: "IX_Posts_BlogId",
table: "Posts",
column: "BlogId");
}
}
5.2 最佳实践清单
- 分页优化:使用
AsNoTracking()
和Skip/Take
- 事务边界:将业务逻辑单元包装在
TransactionScope
中 - 延迟加载:通过
virtual
关键字启用,但需谨慎使用以避免N+1问题 - 多数据库支持:通过
UseXxx()
方法实现,注意SQL方言差异 - 性能监控:使用EF Core Profiler分析查询执行计划
六、EF Core是数据库开发的“瑞士军刀”
通过本文的20+代码示例和深度技术解析,开发者可以:
- 架构设计:选择适合项目的开发模式(Database First/Code First)
- 性能调优:通过NoTracking、分页、索引优化查询速度
- 事务管理:实现分布式事务和跨数据库操作
- 迁移管理:使用EF Core CLI进行版本控制