以下是基于 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://www.pswp.cn/pingmian/96482.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96482.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96482.shtml

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

相关文章

UniApp状态管理深度重构指南

作为专业智能创作助手&#xff0c;我将帮助你逐步理解并实现UniApp状态管理的深度重构。UniApp基于Vue.js框架&#xff0c;其状态管理通常使用Vuex&#xff0c;但随着应用规模扩大&#xff0c;状态管理可能变得臃肿、难以维护。深度重构旨在优化性能、提升可维护性&#xff0c;…

时序数据库:定义与基本特点

在当今的物联网&#xff08;IoT&#xff09;、 DevOps监控、金融科技和工业4.0时代&#xff0c;我们每时每刻都在产生海量的与时间紧密相关的数据。服务器CPU指标、智能电表读数、车辆GPS轨迹、股票交易记录……这些数据都有一个共同的核心特征&#xff1a;时间是它们不可分割的…

linux系统安装wps

在Linux系统上通过deb包安装WPS Office是个不错的选择。下面是一个主要步骤的概览&#xff0c;我会详细介绍每一步以及可能遇到的问题和解决方法。步骤概览关键操作说明/注意事项1. 下载DEB包访问WPS官网下载需选择与系统架构匹配的版本&#xff08;通常是AMD64&#xff09;2. …

git常见冲突场景及解决办法

场景1.假设一开始 本地拉取了远程最新的代码 就是说本地和远程此时一样 然后本地写了一个新需求git commit了 但是没有提交到远程仓库 然后另外一个地方提交了某个功能的新代码 到远程 此时本地和远程的代码不一样了 而且本地有已经 commit的 这时候 这个本地想同步远程的最新代…

Flink面试题及详细答案100道(41-60)- 状态管理与容错

《前后端面试题》专栏集合了前后端各个知识模块的面试题&#xff0c;包括html&#xff0c;javascript&#xff0c;css&#xff0c;vue&#xff0c;react&#xff0c;java&#xff0c;Openlayers&#xff0c;leaflet&#xff0c;cesium&#xff0c;mapboxGL&#xff0c;threejs&…

【二开】CRMEB开源版按钮权限控制

【二开】CRMEB开源版按钮权限控制使用方法v-unique_auth"order-refund"<el-dropdown-itemv-unique_auth"order-refund">立即退款</el-dropdown-item >或者 满足其中一个即可v-unique_auth"[order-delete,order-dels]"通过管理端权限…

AOSP源码下载及编译错误解决

源码下载 软件下载sudo apt-get updatesudo apt-get install gitsudo apt-get install curlsudo apt-get install adbsudo apt-get install reposudo apt-get install vimsudo apt-get install -y git devscripts equivs config-package-dev debhelper-compat golang curl配置g…

实验-高级acl(简单)

实验-高级acl&#xff08;简单&#xff09;预习一、实验设备二、拓扑图三、配置3.1、网络互通3.2、配置ACL3.3、取消配置步骤1&#xff1a;先移除接口上的ACL应用步骤2&#xff1a;修改或删除ACL中的错误规则方法A&#xff1a;直接删除错误规则&#xff08;保留其他正确规则&am…

IoC / DI 实操

1. 建三层类包结构&#xff1a;com.lib ├─ config ├─ controller ├─ service ├─ repository ├─ model └─ annotation // 自定义限定符① 实体 Bookpackage com.lib.model; public class Book {private Integer id;private String title;// 全参构造 gette…

AdsPower RPA 从excel中依次读取多个TikTok账号对多个TikTok账号目标发送信息

多个账号对多个目标发送子场景 B&#xff1a;多个账号向“不同的”目标循环发送&#xff08;最复杂的群发逻辑&#xff09;流程&#xff1a;Excel表中有一个“目标用户”列表。RPA流程会进行嵌套循环&#xff1a;外层循环&#xff1a;遍历Excel中的每一行数据&#xff08;即每一…

扩散模型进化史

一幅精美的图片&#xff0c;一段精彩的视频&#xff0c;可能始于一片纯粹的噪声。 2024年的计算机视觉顶会CVPR上&#xff0c;扩散模型成为绝对主角。从图像生成到视频理解&#xff0c;从超分辨率到3D建模&#xff0c;扩散模型正以惊人的速度重塑着AIGC&#xff08;AI生成内容&…

一次 Linux 高负载 (Load) 异常问题排查实录

一次 Linux 高负载&#xff08;Load&#xff09;异常排查实录一、背景及排查过程材料二、排查分析2.1Load 的真正含义2.2&#xff1a;确认异常进程2.3&#xff1a;线程卡在哪&#xff08;wchan&#xff09;2.4&#xff1a;perf 采样&#xff08;用户态/内核态热点&#xff09;2…

浅析Linux进程信号处理机制:基本原理及应用

文章目录概述信号类型可靠信号与不可靠信号Fatal信号与Non Fatal信号不可捕获/忽略信号信号工作机制信号处理方式信号嵌套处理信号使用信号发送kill命令注册信号处理函数信号安全与函数可重入性可重入函数线程安全与可重入性相关参考概述 Linux信号机制是进程间通信的一种方式…

【学习K230-例程19】GT6700-TCP-Client

B站视频 TCP TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff0c;传输控制协议/网际协议&#xff09;是指能够在多个不同网络间实现信息传输的协议簇。TCP/IP 协议不仅仅指的是 TCP和 IP 两个协议&#xff0c;而是指一个由 FTP、SMTP、TCP、UDP、I…

o2oa待办流程和已办流程表

在o2oa系统中每个用户有两种唯一标识&#xff1a;第一种是姓名个人钉钉ID&#xff08;或者o2oa创建该用户时设置的id&#xff09;ORG_PERSON.xdistinguishedName刘准3013692136672430P第二种是姓名所在部门的钉钉id个人钉钉idORG_IDENTITY.xdistinguishedName刘准966488616_301…

QT零基础入门教程

基础篇第一章 QT 基础认知1.1 什么是 QT&#xff08;What&#xff09;​定义&#xff1a;跨平台 C 应用开发框架&#xff0c;不仅用于 UI 设计&#xff0c;还包含核心功能&#xff08;如事件、网络、数据库&#xff09;。​核心特性&#xff1a;​跨平台&#xff1a;一套代码支…

远程依赖管理新范式:cpolar赋能Nexus全球协作

文章目录 前言一. Docker安装Nexus二. 本地访问Nexus三. Linux安装Cpolar四. 配置Nexus界面公网地址五. 远程访问 Nexus界面六. 固定Nexus公网地址七. 固定地址访问Nexus 前言 Nexus作为一款企业级仓库管理工具&#xff0c;其核心功能在于集中管理各类软件依赖&#xff0c;提供…

Prompt技术深度解析:从基础原理到前沿应用的全面指南

引言 在人工智能技术飞速发展的今天&#xff0c;Prompt技术&#xff08;提示词工程&#xff09;已成为连接人类智慧与机器智能的重要桥梁。随着GPT-4、Claude、Gemini等大型语言模型的广泛应用&#xff0c;如何有效地与这些AI系统进行交互&#xff0c;已成为决定AI应用成功与否…

性能测试工具Jmeter之java.net.BindException: Address already in use

首先请参考连接&#xff1a;https://blog.csdn.net/weixin_46190208/article/details/115229733 。配置完注册表后一般就能解决问题。但并未解决我的问题 注册表的MaxUserPort&#xff0c;TcpTimedWaitDelay两个参数我只能配置MaxUserPort&#xff0c;设置TcpTimedWaitDelay后&…

JDK 新特性

JDK 新特性引入模块Java 9 开始引入了模块&#xff08;Module&#xff09;&#xff0c;目的是为了管理依赖。使用模块可以按需打包 JRE 和进一步限制类的访问权限。接口支持私有方法JAVA 9 开始&#xff0c;接口里可以添加私有方法&#xff0c;JAVA 8 对接口增加了默认方法的支…