查缺補漏系統學習 EF Core 6 - 修改實體數據

推薦關注「碼俠江湖」星標,時刻不忘江湖事

這是 EF Core 系列的第六篇文章,上一篇文章講述了 EF Core 中的原始 SQL 語句查詢。

這篇文章講一講 EF Core 如何修改實體數據。

點擊上方或后方藍字,閱讀 EF Core 系列合集。

b9afbd3d71fb0a836958986cd73cebcb.png

實體狀態

在開始學習 EF Core 修改數據之前,我們必須要熟悉 EF Core 中的一些機制。

前面的內容中,我們講到 DbContext 包括三個屬性:ChangeTrackerDatabaseModel

之前的示例中,DatabaseModel 我們都有用到過,那么 ChangeTracker 是做什么的?

ChangeTracker 屬性提供了對當前加載的實體的,變化跟蹤信息和操作的訪問。

當我們想執行任何數據庫修改操作時,無論是創建、修改還是刪除一個實體,EF Core 都有關于跟蹤和操作的信息。

為什么要保存這些信息呢?

因為在 EF Core 中,修改實體屬性的值,并不會直接被保存到數據庫中。

而是要我們調用 SaveChanges 方法,EF Core 才會將修改反應到數據庫,在此之前,EF Core 不會執行任何操作。

因此,在調用 SaveChanges 方法之前, EF Core 需要知道我們都執行了什么操作,這對 EF Core 來說非常重要。

每一個被追蹤的實體,都有附屬于它的 State 屬性。

當我們使用上下文對象加載實體,而不使用 AsNoTracking 方法時,或者我們通過 UpdateRemoveAdd 方法,改變實體狀態時,該實體都會成為被跟蹤的實體。

狀態屬性的值可以通實體的 State 方法獲得。

那么實體的狀態有哪些呢?

  • 「Detached」 - 該實體沒有被追蹤,調用 SaveChanges 方法不會有任何效果

  • 「Unchanged」 - 該實體從數據庫中加載,但沒有任何變化。調用 SaveChanges 方法也不會有任何效果

  • 「Added」 - 該實體不存在于數據庫中,調用 SaveChanges 方法會將其添加到數據庫中。

  • 「Modified」 - 該實體存在于數據庫中,并被修改過,因此,調用 SaveChanges 方法將在數據庫中修改它

  • 「Deleted」 - 該實體存在于數據庫中,調用 SaveChanges 方法,會將它從數據庫中刪除。

實體操作

接下來,讓我們結合示例來演示增刪改,并觀察實體狀態的變化:

var?account?=?new?Account
{Name?=?"張三",Age?=?18
};
_context.Add(account);
_context.SaveChanges();

示例中,首先創建了一個 account 對象,此時它還未被附加到 EF Core 上下文中,它的狀態應該是 Detached

當我們使用 Add 方法,將account對象作為實體添加到上下文后,它的狀態應該是 Added

緊接著,使用 SaveChanges 方法,將新添加的實體,保存到數據庫中,它的狀態應該是 Unchanged

當我們再次修改實體中的任意屬性時,它的狀態會變成 Modified

//?...
account.Age?=?20;
_context.SaveChanges();

使用 SaveChanges 方法,將已修改的實體,應用到數據庫時,它的狀態又會變回 Unchanged

最后,當我們從上下文中刪除這個實體后,實體的狀態會變成 Deleted

//?...
_context.Remove(account);
_context.SaveChanges();

再次使用 SaveChanges 方法,將實體從數據庫中徹底刪除,大家想一想,此時它的狀態依然會變成什么?

這次可不是 Unchanged 了,因為它已經從上下文中被移除了,所以它的狀態是 Detached

EF Core 正是用這么幾個方法,對實體進行增刪改。

當然,這只是其中一種方式。

在這個示例中,新增的對象經過 Add 方法,被添加到了上下文。

之后的更新和刪除操作,都是針對實體已經存在于上下文中的情況。

那么如果,我們有一個對象,它不存在于上下文中,但它確實存在于數據庫中,我們該如何對它就行更新或刪除呢?

首先,你肯定不能用 Add 方法,雖然它可以將一個對象,作為實體添加到上下文中

但它還會使實體狀態成為 Added,而不是 Modified,這種情況下執行 SaveChanges 方法,EF Core 只會生成插入數據的語句,肯定會造成數據庫沖突,因為數據已存在。

比如,這個對象:

var?account?=?new?Account
{Id?=?new?Guid("dd4feb0b-b57c-4338-a40a-7aa73fc6e460"),Name?=?"Zilor",Age?=?99
};

實際開發中,它可能來自的客戶端,這個對象的數據是經過之前的查詢得到的。

現在客戶端對它的屬性進行了修改,主鍵肯定是不會變的。

此時,它的狀態是 Detached,沒有被附加到上下文中,我們該如何直接更新到數據庫呢?

這里有兩種方法可以做到:

一是先用 ID 從 EF Core 中查詢出實體,然后用 account 對象中的屬性值,修改實體中的值,再使用 SaveChanges 保存數據。

比如這樣:

var?dbAccount?=?_context.Accounts.FirstOrDefault(a?=>?a.Id?==?account.Id);
dbAccount.Name?=?account.Name;
dbAccount.Age?=?account.Age;
_context.SaveChanges();

需要注意的是,如果修改的操作,沒有造成實體值的任何變化,實體狀態將仍是 Unchanged

此時,即便執行SaveChanges方法, 也不會有任何效果。

二是用附加方法,將 account 對象附加到上下文,然后手動修改它的狀態,再使用 SaveChanges 保存數據。

比如這樣:

var?account?=?new?Account
{Id?=?new?Guid("dd4feb0b-b57c-4338-a40a-7aa73fc6e460"),Name?=?"Zilor",Age?=?99
};_context.Accounts.Attach(account);
_context.Entry(account).State?=?EntityState.Modified;
_context.SaveChanges();

Attach 方法用來附加實體,被附加的實體初始狀態為 Unchanged,所以我們要手動修改實體狀態。

執行應用,可以看到實體狀態的流轉。

第二種方式相對第一種方式,少了一步查詢,也少了實體屬性的賦值。

但是,無論實體的值相對于數據庫是否有變化,更新操作都會執行。

這是方式適合全量更新,因為如果客戶端傳來的是不完整的對象,只包含了修改的屬性,那么更新時可能會造成問題。

比如這個例子,如果 Account 對象中沒有 Age 屬性,更新到數據庫時,Age 列的值會是個 「Null」

第一種方式,由于是從實體查詢出來的數據,數據是完整的,修改也只是針對個別屬性,所以保存數據時,不會發生這種情況。

而且第一種方式,可以判斷出實體是否真的已經修改,無修改的話,不會執行任何操作。

所以,對于更新操作,建議使用第一種方式,更安全也更靠譜;

刪除操作也是如此,只需要將實體狀態修改為 Deleted,就可以直接刪除,不夠刪除操作可以使用第二種方式。

更多精彩內容,請關注我▼▼

c86db9f4bb0281dee67532f2e4f97ec6.gif

如果喜歡我的文章,那么

在看和轉發是對我最大的支持!

(戳下面藍字閱讀)

e4390b71d0dd332557a03d3060e4db56.png

推薦關注微信公眾號:碼俠江湖

? ? ? ? ? ? ? ? ? ? ? ??a7606bd73dcef202e659b3be38047415.png覺得不錯,點個在看再走喲

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/287462.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/287462.shtml
英文地址,請注明出處:http://en.pswp.cn/news/287462.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

在AngularJS的controller外部直接獲取$scope

為了防止無良網站的爬蟲抓取文章,特此標識,轉載請注明文章出處。LaplaceDemon/SJQ。 http://www.cnblogs.com/shijiaqi1066/p/5560843.html 以前利用webqq的寫過一個自動發消息的腳本,由于那時webqq還直接使用類似jQuery操作DOM的技術&#x…

js pug 代碼_pug模版學習(一)

標簽按照html的縮進格式doctype htmlhtmlheadtitlebody編譯結果:文本p 這是文本| 這是文本p.這是文本編譯結果:這是文本這是文本這是文本屬性設置class名跟id名(默認是div)p.foop#foop#foo.foo.foo#foo編譯結果:其他屬性:a(href&q…

Upgrade Hole puncher Mathematical Modeling

// AntColony.cpp : 定義控制臺應用程序的入口點。 //#include<iostream> #include<math.h> #include<time.h> #include<stdio.h> #include <fstream> #include <string> #include <iostream> #include <vector>using n…

Android之提示Cannot call this method while RecyclerView is computing a layout or scrolling

1 問題 java.lang.IllegalStateException: Cannot call this method while RecyclerView is computing a layout or scrolling androidx.recyclerview.widget.RecyclerView{24d6f3b VFED.V... ......ID 0,657-1074,1911 #7f090143 app:id/recyclerView}, adapter:com.appsinno…

Java8新的異步編程方式 CompletableFuture(三)

前面兩篇文章已經整理了CompletableFuture大部分的特性&#xff0c;本文會整理完CompletableFuture余下的特性&#xff0c;以及將它跟RxJava進行比較。 3.6 Either Either 表示的是兩個CompletableFuture&#xff0c;當其中任意一個CompletableFuture計算完成的時候就會執行。 …

情人節,我表白了CSDN小姐姐后,竟然...【為表白寫了一個繪圖工具,讓我不再手殘】

情人節&#xff0c;我表白了CSDN小姐姐后&#xff0c;竟然…竟然有人看了這篇文。 以下圖片素材由一個還沒寫完的工具繪制&#xff0c;稍后會放在CSDN的代碼倉庫&#xff08;現在能用了&#xff0c;還沒時間改&#xff0c;顏色填充算法還沒寫&#xff0c;有能力的朋友可以修改一…

【小程序】劉一哥課堂隨機點名提問神器V1.0(附源程序)

為了能讓我們的孩子們盡量來教室上課,增強課堂的參與度,激發課堂激情,提高學習效率,一哥也是煞費苦心,于是開發出了這么一款課堂點名提問神器,跟大家分享一下。 打開神器,看到的界面是這樣子的,我很感激有勇氣按時起床并能到教室的每一位有志之士。 點擊【開始】按鈕,…

org.hibernate.HibernateException: No Session found for current thread

spring、springmvc和hibernate整合 在sessionFactory.getCurrentSession()時&#xff0c;出現以下異常 No Session found for current thread但使用sessionFactory.openSession()是沒有任何問題的 嚴重: Servlet.service() for servlet [springDispatcherServlet] in context w…

java mysbatis select_MyBatis SELECT基本查詢實現方法詳解

1、返回一個LISTselect * from tbl_employee where last_name like #{lastName}2、將查詢記錄封裝為一個Mapselect * from tbl_employee where id#{id}返回一條記錄的map&#xff1b;key就是列名&#xff0c;值就是對應的值。3、多條記錄封裝為一個mapMapKey("id")pu…

Git之怎么通過命令修改前面幾次提交的記錄

1 問題 我們平時用gitlab,github發現提交代碼上庫記錄寫錯了&#xff0c;需要修改回來。 2 解決辦法

Git客戶端TortoiseGit(Windows系統)的使用方法

本文環境&#xff1a; 操作系統&#xff1a;Windows XP SP3 Git客戶端&#xff1a;TortoiseGit-1.8.8.0-32bit 一、安裝Git客戶端 全部安裝均采用默認&#xff01; 1. 安裝支撐軟件 msysgit: https://code.google.com/p/msysgit/downloads/list?qfullinstallerofficialgit 當前…

.Net 在容器中操作宿主機

1方案描述 在 docker 容器中想操作宿主機&#xff0c;一般會使用 ssh 的方式&#xff0c;然后 .Net 通過執行遠程 ssh 指令來操作宿主機。本文將使用 交互式 .Net 容器版 中提供的鏡像演示 .Net 在容器中如何操作宿主機。2前期準備 1. 宿主機上生成 ssh key生成 ss…

【看動漫學編程】程序員在異世界生個娃 第1篇:太極村

前言 作者文筆比較水&#xff0c;還請見諒。 以下內容還將使用視頻動態漫畫表現&#xff0c;剪輯完將會貼出鏈接。 小說劇情為劇情需要&#xff0c;過渡到知識點&#xff0c;部分篇幅可能沒有技術知識點還望諒解。 由于沒有經費支持&#xff0c;所以畫出來的東西是我自己用代碼…

【ArcGIS風暴】最牛逼空間數據批處理神器來了:用戶自定義工具箱GeoStorm.tbx

【Warming up】在學習和工作的過程中,作者曾寫過很多采用ArcGIS模型構建器(Model Builder)、Python代碼等批處理方法(感興趣的GISers可以去【測繪地理信息Big風暴專】欄去交流學習指導),大大的減輕了操作壓力,提高了工作效率。今天給大家展示一款神器:自定義工具箱GeoS…

2.6. PostgreSQL表之間連接

到目前為止&#xff0c;我們的查詢一次只訪問了一個表。查詢可以一次訪問多個表&#xff0c;或者用某種方式訪問一個表&#xff0c;而同時處理該表的多個行。一個同時訪問同一個或者不同表的多個行的查詢叫連接查詢。舉例來說&#xff0c;比如你想列出所有天氣記錄以及這些記錄…

Android之Caused by: java.lang.IllegalArgumentException: Failed to find configured root that contains

1 問題 用takePhoto去照相的時候特么的一打開就報這個錯誤 2020-04-09 21:33:49.124 19016-19016/com.appsinnova.android.keepshare E/AndroidRuntime: FATAL EXCEPTION: mainProcess: com.appsinnova.android.keepshare, PID: 19016java.lang.RuntimeException: Unable to …

Linux下c/c++項目代碼覆蓋率的產生方法

最近做了一系列的單元測試相關的工作&#xff0c;除了各種規范及測試框架以外&#xff0c;討論比較多的就是關于代碼覆蓋率的產生&#xff0c;c/c與其他的一些高級語言或者腳本語言相比較而言&#xff0c;例如 Java、.Net和php/python/perl/shell等&#xff0c;由于沒有這些高級…

C# WPF從后臺代碼生成行列可變的表格

z概述WPF常用的表格控件是DataGrid&#xff0c;這個控件在前臺XAML編寫的話&#xff0c;一般列已經固定&#xff0c;然后給每個列去綁定數據&#xff0c;但是如果我的列不固定&#xff0c;隨著運算結果變動呢&#xff1f;這時候DataGrid&#xff0c;就比較難實現這個需求&#…

軟件架構實踐文章鏈接

2019獨角獸企業重金招聘Python工程師標準>>> 架構 InfoQ: 又拍網架構中的分庫設計 SNS網站數據庫技術分析 - 51CTO.COM 數據庫水平切分的實現原理解析 - iBATIS - Java - JavaEye論壇 基于amoeba的mysql分布式數據庫學習&#xff08;一&#xff09; - Java - JavaEy…

【看動漫學編程】程序員在異世界生個娃 第2篇:外掛已準備就緒

前言 作者文筆比較水&#xff0c;還請見諒。 以下內容還將使用視頻動態漫畫表現&#xff0c;剪輯完將會貼出鏈接。 小說劇情為劇情需要&#xff0c;過渡到知識點&#xff0c;部分篇幅可能沒有技術知識點還望諒解。 由于沒有經費支持&#xff0c;所以畫出來的東西是我自己用代碼…