当前位置: 首页 > news >正文

C# Entity Framework Core 的 CRUD 操作与关联查询实战示例

以下是基于 Entity Framework Core 的 CRUD 操作与关联查询实战示例,以 用户(User)订单(Order) 实体为例(一对多关系),包含完整代码和操作说明。

一、基础准备

1. 实体类定义(沿用之前的数据注解配置)
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
​
// 用户实体
public class User
{[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]public int UserId { get; set; }
​[Required][StringLength(50)]public string UserName { get; set; }
​[Required][DataType(DataType.EmailAddress)]public string Email { get; set; }
​[Timestamp]public byte[] RowVersion { get; set; }
​// 导航属性:一个用户包含多个订单public ICollection<Order> Orders { get; set; } = new List<Order>();
}
​
// 订单实体
public class Order
{[Key][DatabaseGenerated(DatabaseGeneratedOption.Identity)]public int OrderId { get; set; }
​[Required][Column(TypeName = "decimal(18,2)")]public decimal Amount { get; set; }
​public DateTime OrderTime { get; set; } = DateTime.Now;
​// 外键:关联用户[ForeignKey("User")]public int UserId { get; set; }
​// 导航属性:一个订单属于一个用户public User User { get; set; }
}
2. DbContext 定义(数据库上下文)
using Microsoft.EntityFrameworkCore;
​
public class AppDbContext : DbContext
{// 数据集(对应数据库表)public DbSet<User> Users { get; set; }public DbSet<Order> Orders { get; set; }
​// 配置数据库连接(示例使用 SQL Server LocalDB)protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EfCrudDemo;Trusted_Connection=True;");}
​// 可选:用 Fluent API 补充配置(与数据注解不冲突,优先级更高)protected override void OnModelCreating(ModelBuilder modelBuilder){// 配置 User 与 Order 的一对多关系modelBuilder.Entity<Order>().HasOne(o => o.User).WithMany(u => u.Orders).HasForeignKey(o => o.UserId).OnDelete(DeleteBehavior.Cascade); // 级联删除:删除用户时删除其所有订单}
}

二、CRUD 操作实战

以下示例封装了用户和订单的 CRUD 操作,使用异步方法(EF 推荐)并处理常见异常。

1. 创建操作(Create)
using System.Threading.Tasks;
​
public class CrudService
{private readonly AppDbContext _context;
​// 依赖注入 DbContextpublic CrudService(AppDbContext context){_context = context;}
​// 创建用户public async Task<User> CreateUserAsync(string userName, string email){var user = new User{UserName = userName,Email = email};
​_context.Users.Add(user);await _context.SaveChangesAsync(); // 提交到数据库return user;}
​// 为用户创建订单public async Task<Order> CreateOrderAsync(int userId, decimal amount){// 先验证用户是否存在var user = await _context.Users.FindAsync(userId);if (user == null)throw new KeyNotFoundException("用户不存在");
​var order = new Order{UserId = userId,Amount = amount,OrderTime = DateTime.Now};
​_context.Orders.Add(order);await _context.SaveChangesAsync();return order;}
}
2. 读取操作(Read)

包括单条查询、列表查询、条件查询,以及关联查询(核心)。

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
​
public class QueryService
{private readonly AppDbContext _context;
​public QueryService(AppDbContext context){_context = context;}
​// 1. 查询单个用户(不含关联订单)public async Task<User> GetUserByIdAsync(int userId){return await _context.Users.FindAsync(userId);}
​// 2. 关联查询:查询用户及其所有订单(一对多关联)public async Task<User> GetUserWithOrdersAsync(int userId){// 使用 Include 加载关联的 Orders 集合return await _context.Users.Include(u => u.Orders) // 关键:加载导航属性.FirstOrDefaultAsync(u => u.UserId == userId);}
​// 3. 关联查询:查询订单及其所属用户public async Task<Order> GetOrderWithUserAsync(int orderId){return await _context.Orders.Include(o => o.User) // 加载订单关联的 User.FirstOrDefaultAsync(o => o.OrderId == orderId);}
​// 4. 条件查询:查询金额大于 100 的订单及用户public async Task<List<Order>> GetHighValueOrdersAsync(decimal minAmount){return await _context.Orders.Include(o => o.User).Where(o => o.Amount > minAmount).OrderByDescending(o => o.OrderTime).ToListAsync();}
​// 5. 分页查询:查询用户列表(每页 10 条)public async Task<List<User>> GetUsersByPageAsync(int pageIndex, int pageSize){return await _context.Users.Skip((pageIndex - 1) * pageSize) // 跳过前面的页.Take(pageSize) // 取当前页数据.ToListAsync();}
}
3. 更新操作(Update)
public async Task<bool> UpdateUserAsync(int userId, string newUserName, string newEmail)
{// 方式1:先查询再更新(推荐,可避免并发问题)var user = await _context.Users.FindAsync(userId);if (user == null)return false;
​user.UserName = newUserName;user.Email = newEmail;
​// EF 会自动跟踪实体变化,无需显式调用 Updateawait _context.SaveChangesAsync();return true;
​// 方式2:直接附加实体更新(适合已知实体完整信息的场景)// var user = new User { UserId = userId, UserName = newUserName, Email = newEmail };// _context.Users.Update(user); // 显式标记为修改// await _context.SaveChangesAsync();
}
​
// 更新订单金额(含并发控制)
public async Task<bool> UpdateOrderAmountAsync(int orderId, decimal newAmount, byte[] rowVersion)
{var order = await _context.Orders.FindAsync(orderId);if (order == null)return false;
​// 并发控制:检查时间戳是否匹配(防止多人同时修改)_context.Entry(order).Property("RowVersion").OriginalValue = rowVersion;
​order.Amount = newAmount;try{await _context.SaveChangesAsync();return true;}catch (DbUpdateConcurrencyException){// 并发冲突处理(如提示用户数据已被修改)return false;}
}
4. 删除操作(Delete)
// 删除用户(级联删除其所有订单,在 OnModelCreating 中配置)
public async Task<bool> DeleteUserAsync(int userId)
{var user = await _context.Users.FindAsync(userId);if (user == null)return false;
​_context.Users.Remove(user);await _context.SaveChangesAsync();return true;
}
​
// 删除单个订单
public async Task<bool> DeleteOrderAsync(int orderId)
{// 方式1:先查询再删除// var order = await _context.Orders.FindAsync(orderId);// if (order != null) _context.Orders.Remove(order);
​// 方式2:直接构造实体删除(性能更优,无需查询)var order = new Order { OrderId = orderId };_context.Orders.Remove(order);
​await _context.SaveChangesAsync();return true;
}

三、关联查询高级场景

1. 过滤关联数据(只加载符合条件的订单)
// 查询用户及其金额大于 500 的订单
public async Task<User> GetUserWithHighValueOrdersAsync(int userId)
{return await _context.Users.Include(u => u.Orders.Where(o => o.Amount > 500)) // 过滤关联集合.FirstOrDefaultAsync(u => u.UserId == userId);
}
2. 多级关联查询(假设有三级实体:Order → OrderItem)
// 实体类补充:OrderItem(订单明细)
public class OrderItem
{public int Id { get; set; }public string ProductName { get; set; }public decimal Price { get; set; }public int OrderId { get; set; }public Order Order { get; set; }
}
​
// 查询订单及其用户、订单明细(三级关联)
public async Task<Order> GetOrderWithDetailsAsync(int orderId)
{return await _context.Orders.Include(o => o.User) // 一级关联:用户.Include(o => o.OrderItems) // 二级关联:订单明细.FirstOrDefaultAsync(o => o.OrderId == orderId);
}

四、使用示例(控制台 / API)

// 初始化服务(实际项目中推荐依赖注入)
using var context = new AppDbContext();
var crudService = new CrudService(context);
var queryService = new QueryService(context);
​
// 1. 创建用户和订单
var user = await crudService.CreateUserAsync("张三", "zhangsan@example.com");
var order1 = await crudService.CreateOrderAsync(user.UserId, 299.99m);
var order2 = await crudService.CreateOrderAsync(user.UserId, 899.99m);
​
// 2. 关联查询:查询用户及其所有订单
var userWithOrders = await queryService.GetUserWithOrdersAsync(user.UserId);
Console.WriteLine($"用户 {userWithOrders.UserName} 的订单数:{userWithOrders.Orders.Count}");
​
// 3. 更新用户信息
await crudService.UpdateUserAsync(user.UserId, "张三三", "zhangsan3@example.com");
​
// 4. 删除订单
await crudService.DeleteOrderAsync(order1.OrderId);

五、关键注意事项

  1. 关联数据加载

    • 显式加载:使用 Include(立即加载)或 ThenInclude(多级加载)。

    • 延迟加载:在导航属性加 virtual 并配置 UseLazyLoadingProxies(),但可能导致 N+1 查询问题,谨慎使用。

  2. 并发控制: 使用 [Timestamp] 标记的字段可自动处理并发,SaveChanges 时若发现数据已被修改会抛出 DbUpdateConcurrencyException

  3. 性能优化

    • 避免加载不必要的字段:使用 Select 投影(_context.Users.Select(u => new { u.UserId, u.UserName }))。

    • 分页查询:Skip() + Take() 减少数据传输量。

    • 批量操作:复杂批量更新 / 删除推荐用 EF Core Bulk Extensions 库提升性能。

通过以上示例,可掌握 EF Core 中 CRUD 操作和关联查询的核心用法,覆盖大部分日常开发场景。


文章转载自:

http://9g1uCO64.dbjyb.cn
http://XN0qB4Pn.dbjyb.cn
http://2MHwgoH2.dbjyb.cn
http://a8qahRoE.dbjyb.cn
http://Cx0ui4js.dbjyb.cn
http://71Q9wA3l.dbjyb.cn
http://gLkI95bf.dbjyb.cn
http://gqaf85XC.dbjyb.cn
http://dnDYAjHC.dbjyb.cn
http://hzwLS95k.dbjyb.cn
http://H7GGBHo7.dbjyb.cn
http://Yu8jepEd.dbjyb.cn
http://obqrMvba.dbjyb.cn
http://MnV87gnc.dbjyb.cn
http://Eji32oXm.dbjyb.cn
http://MUPqCVhI.dbjyb.cn
http://MczUJWWh.dbjyb.cn
http://EXWM65Ht.dbjyb.cn
http://oackVO00.dbjyb.cn
http://xGeAfrBR.dbjyb.cn
http://dOurfzW0.dbjyb.cn
http://ZQ0tUO57.dbjyb.cn
http://A90bXST8.dbjyb.cn
http://BXTA07HO.dbjyb.cn
http://67Oe7mhH.dbjyb.cn
http://XtOhyiZC.dbjyb.cn
http://tFCgiTiZ.dbjyb.cn
http://Tr7z1WkX.dbjyb.cn
http://cW6o37DE.dbjyb.cn
http://HvPSBkvW.dbjyb.cn
http://www.dtcms.com/a/382195.html

相关文章:

  • java后端工程师进修ing(研一版‖day44)
  • 部署 LVS-DR 群集
  • 事务学习总结
  • IP协议相关特性
  • 贪心算法应用:高频订单流平衡问题详解
  • Win系统下配置PCL库第四步之LASlib文件配置(超详细)
  • 软考-局域网基础考点总结
  • Asio C++ Library是用来做什么的
  • 深度学习在智能车辆故障诊断中的应用
  • DeepFace 全面使用教程
  • ISP之DHCPv6-PD(前缀代理)为用户下发前缀
  • LINUX913 shell:set ip [lindex $argv 0],\r,send_user,spawn ssh root@ip “cat “
  • GEO 优化专家孟庆涛以 AI 技术建体系,赋能多行业智能化转型
  • 没有统一的知识管理平台会带来哪些问题
  • 系统编程day10-同步与互斥
  • Spring Boot 整合 Mockito 进行单元测试
  • 【C++】C++11介绍(Ⅱ)
  • HTML新属性
  • 分库分表是否真的要退出历史舞台?
  • [BJ2012.X4] 统计车牌
  • 【Rust】一个从Modelscope下载模型CLI工具
  • 第三方服务商接入美团核销接口:零侵入对接的关键要点
  • 电压监控器原理
  • python面向对象的三大特性
  • 从 MySQL 到 TiDB:分布式数据库的无缝迁移与实战指南
  • Ansible的jinja2 模板、Roles角色详解
  • Linux内核的PER_CPU机制
  • 树莓派组建nas,云服务器及家庭影院
  • 二叉树hot100-中等
  • MX 模拟赛二总结