Entity Framework (EF) 是.NET平台最流行的对象关系映射(ORM)框架,它简化了数据库交互,让开发者能够以面向对象的方式操作数据。本文将全面介绍EF Core的使用方法,帮助您高效地进行数据访问开发。
一、Entity Framework Core基础
1.1 EF Core简介
Entity Framework Core是轻量级、可扩展、跨平台版的EF,主要特点包括:
- 支持LINQ查询
- 变更跟踪
- 数据库迁移
- 跨平台支持
1.2 安装与配置
通过NuGet安装核心包:
Install-Package Microsoft.EntityFrameworkCore.SqlServer
基本DbContext配置:
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public DbSet<Category> Categories { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
@"Server=(localdb)\mssqllocaldb;Database=EfCoreDemo;Trusted_Connection=True");
}
}
二、数据模型定义
2.1 实体类配置
基本实体类示例:
public class Product
{
public int Id { get; set; } // 主键
public string Name { get; set; }
public decimal Price { get; set; }
public DateTime CreatedDate { get; set; } = DateTime.UtcNow;
// 导航属性
public int CategoryId { get; set; }
public Category Category { get; set; }
}
2.2 数据注解配置
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("Products")]
public class Product
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProductId { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
[Column(TypeName = "decimal(18,2)")]
public decimal Price { get; set; }
}
2.3 Fluent API配置
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.ToTable("Products")
.HasKey(p => p.Id);
modelBuilder.Entity<Product>()
.Property(p => p.Name)
.IsRequired()
.HasMaxLength(100);
modelBuilder.Entity<Product>()
.HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
}
三、基本CRUD操作
3.1 创建数据
using (var context = new AppDbContext())
{
var category = new Category { Name = "电子产品" };
var product = new Product
{
Name = "智能手机",
Price = 2999.99m,
Category = category
};
context.Products.Add(product);
int recordsAffected = context.SaveChanges();
Console.WriteLine($"影响了{recordsAffected}条记录");
}
3.2 查询数据
基本查询:
// 获取所有产品
var products = context.Products.ToList();
// 条件查询
var expensiveProducts = context.Products
.Where(p => p.Price > 1000)
.OrderByDescending(p => p.Price)
.ToList();
包含导航属性:
var productsWithCategory = context.Products
.Include(p => p.Category)
.ToList();
3.3 更新数据
var product = context.Products.FirstOrDefault(p => p.Id == 1);
if (product != null)
{
product.Price = 2599.99m;
context.SaveChanges();
}
3.4 删除数据
var product = context.Products.Find(1);
if (product != null)
{
context.Products.Remove(product);
context.SaveChanges();
}
四、高级查询技术
4.1 复杂LINQ查询
var result = from p in context.Products
join c in context.Categories on p.CategoryId equals c.Id
where p.Price > 500 && c.Name.Contains("电子")
orderby p.Price descending
select new
{
p.Name,
p.Price,
CategoryName = c.Name
};
4.2 原生SQL查询
执行查询:
var products = context.Products
.FromSqlRaw("SELECT * FROM Products WHERE Price > {0}", 500)
.ToList();
执行存储过程:
var products = context.Products
.FromSqlRaw("EXEC GetExpensiveProducts @minPrice={0}", 1000)
.ToList();
4.3 延迟加载与显式加载
延迟加载(需安装额外包):
// 安装包
Install-Package Microsoft.EntityFrameworkCore.Proxies
// 启用延迟加载
optionsBuilder.UseLazyLoadingProxies();
// 使用
var product = context.Products.First();
var categoryName = product.Category.Name; // 自动加载Category
显式加载:
var product = context.Products.First();
context.Entry(product)
.Reference(p => p.Category)
.Load();
五、数据库迁移
5.1 创建和应用迁移
# 安装EF Core工具(如未安装)
dotnet tool install --global dotnet-ef
# 创建迁移
dotnet ef migrations add InitialCreate
# 应用迁移
dotnet ef database update
5.2 自定义迁移
public partial class AddProductDescription : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Description",
table: "Products",
type: "nvarchar(500)",
maxLength: 500,
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Description",
table: "Products");
}
}
六、性能优化
6.1 查询优化技巧
// 只选择需要的字段
var productNames = context.Products
.Select(p => p.Name)
.ToList();
// 使用AsNoTracking避免变更跟踪
var readOnlyProducts = context.Products
.AsNoTracking()
.ToList();
// 批量操作
context.BulkInsert(products); // 使用Z.EntityFramework.Extensions等库
6.2 连接池配置
services.AddDbContextPool<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")),
poolSize: 128); // 连接池大小
七、实际应用模式
7.1 仓储模式实现
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
Task<T> GetByIdAsync(int id);
Task AddAsync(T entity);
Task UpdateAsync(T entity);
Task DeleteAsync(T entity);
}
public class EfRepository<T> : IRepository<T> where T : class
{
private readonly AppDbContext _context;
public EfRepository(AppDbContext context)
{
_context = context;
}
public IQueryable<T> GetAll() => _context.Set<T>();
public async Task<T> GetByIdAsync(int id) => await _context.Set<T>().FindAsync(id);
public async Task AddAsync(T entity)
{
await _context.Set<T>().AddAsync(entity);
await _context.SaveChangesAsync();
}
// 其他方法实现...
}
7.2 工作单元模式
public interface IUnitOfWork : IDisposable
{
IRepository<Product> Products { get; }
IRepository<Category> Categories { get; }
Task<int> CommitAsync();
}
public class UnitOfWork : IUnitOfWork
{
private readonly AppDbContext _context;
public UnitOfWork(AppDbContext context)
{
_context = context;
Products = new EfRepository<Product>(_context);
Categories = new EfRepository<Category>(_context);
}
public IRepository<Product> Products { get; }
public IRepository<Category> Categories { get; }
public async Task<int> CommitAsync() => await _context.SaveChangesAsync();
public void Dispose() => _context.Dispose();
}
八、常见问题解决
8.1 并发冲突处理
乐观并发控制:
// 实体类添加并发令牌
public class Product
{
[Timestamp]
public byte[] RowVersion { get; set; }
}
// 处理并发异常
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValues = await entry.GetDatabaseValuesAsync();
// 解决冲突逻辑...
}
8.2 连接泄露问题
正确使用DbContext:
// 在ASP.NET Core中依赖注入DbContext(自动管理生命周期)
services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Default")));
// 在其他场景中使用using
using (var context = new AppDbContext())
{
// 操作数据库
}
结语
Entity Framework Core作为.NET生态中的主流ORM框架,大大简化了数据访问层的开发。通过本教程,您应该已经掌握:
- EF Core基础配置:DbContext配置、实体映射
- 核心数据操作:CRUD操作、复杂查询
- 高级特性:迁移管理、性能优化
- 架构模式:仓储模式、工作单元模式
实际开发中建议:
- 根据项目规模选择合适的架构模式
- 注意DbContext的生命周期管理
- 对性能敏感的操作考虑原生SQL或存储过程
- 定期检查并优化生成的SQL查询
随着.NET平台的持续发展,EF Core也在不断进化。建议开发者关注官方文档,及时了解新特性和最佳实践。