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://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 對接口增加了默認方法的支…