一篇文章告訴你如何使用EF CodeFirst做增刪改查

来源:http://www.cnblogs.com/c-o-d-e/archive/2016/02/04/5180830.html
-Advertisement-
Play Games

一、修改數據 其實修改涉及的內容挺多的,是相對於其他操作來說比較繁瑣。也是本文的重頭戲。 雖然都是基礎內容,但是也是值得細細品味的。 1、最簡單直接的修改數據就是從資料庫里檢索出數據修改相應的欄位即可 數據表: Code: using (var db = new ApplicationDbConte


一、修改數據

其實修改涉及的內容挺多的,是相對於其他操作來說比較繁瑣。也是本文的重頭戲。

雖然都是基礎內容,但是也是值得細細品味的。

1、最簡單直接的修改數據就是從資料庫里檢索出數據修改相應的欄位即可

數據表:

 

Code:

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two old_entity = db.Twos.Single(t => t.Text == "90");

old_entity.Text = "update";

db.SaveChanges();

}

結果:

 

2、直接更新不需要檢索出數據

數據表:

 

Code:

通過修改實體的狀態來實現

ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Modified;

db.SaveChanges();

}

結果:

 

這個方式有個不好地方,圖中很明顯的標註出來了,就是會一股腦更新全部欄位,沒有值就被更新成NULL。

3、指定欄位更新

數據表:

 

Code

修改實體狀態為Unchanged.

設置指定屬性的狀態為修改

ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Unchanged;

db.Entry(entity).Property("Text").IsModified = true;

db.SaveChanges();

}

結果:

 

4、禁用驗證實體的有效性

有時我們在更新時有些欄位是不更新的,但是這些欄位又可能會有一些驗證特性,比如不可以為空,這樣我們在保存時會因實體驗證不通過而報錯。

實體:

Uu是必須的,不可為空

public class MyFirst

{

public int MyFirstId { get; set; }

public string Text { get; set; }

[Required]

public string Uu { get; set; }

}

Code:

ApplicationDbContext.MyFirst entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Unchanged;

db.Entry(entity).Property("Text").IsModified = true;

db.SaveChanges();

}

結果:

因沒通過Uu的特性的驗證而報錯了,我們只更新了Text,沒有給Uu賦值,但是Uu又是不可以為空的

 

只要我們在保存前取消這種驗證就可以了,在保存後恢復驗證

修改後的Code:

ApplicationDbContext.MyFirst entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Unchanged;

db.Entry(entity).Property("Text").IsModified = true;

db.Configuration.ValidateOnSaveEnabled = false;

db.SaveChanges();

db.Configuration.ValidateOnSaveEnabled = true;

}

數據表:

 

結果:

 

5、在不同的上下文中更新數據

情況一

Code:

ApplicationDbContext.Two entity;

using(var db1=new ApplicationDbContext())

{

entity = db1.Twos.Single(m => m.Text == "90");

}

entity.Text = "update";

using (var db = new ApplicationDbContext())

{

DbEntityEntry entry = db.Entry(entity);

entry.State = EntityState.Modified;

db.SaveChanges();

}

在這種場景下更新有一個問題是,數據會全部更新,並不是我們指定的Text更新,原因是不在一個上下文中,在另一個上下文中沒有上一個上下文的狀態,所以更新時沒法判定就全部更新了。

數據圖:

 

在db1獲取數據時設置一個斷點,手動修改資料庫後的數據表:

 

結果數據:

會發現數據都被更新了,對比第二張圖

 

情況二

Code:

ApplicationDbContext.Two entity;

using(var db1=new ApplicationDbContext())

{

entity = db1.Twos.Single(m => m.Text == "90");

}

entity.Text = "update";

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity);

entry.State = EntityState.Modified;

db.SaveChanges();

}

在這種場景下,與上面的區別是第二個上下文也檢索了數據,這種情況就是報錯,原因就是同一個上下文中不能出現主鍵值相同的實體。db檢索數據時存在了一個實體在上下文中,又要把db1檢索出的實體添加到db上下文中,一但主鍵值相同就會報錯

 

解決上述情況:

關鍵點是entry.CurrentValues.SetValues(entity);設置當前上下文實體的值。

Code:

ApplicationDbContext.Two entity;

using(var db1=new ApplicationDbContext())

{

entity = db1.Twos.Single(m => m.Text == "90");

}

entity.Text = "update";

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity1);

entry.CurrentValues.SetValues(entity);

db.SaveChanges();

}

數據圖:

 

在db獲取數據時設置一個斷點,手動修改資料庫後的數據表:

 

結果數據:

會發現只有指定的數據更新了,對比第二張圖

 

6、同一個上下文中有實體存在的情況下用外部數據更新

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };           

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity);

entry.State = EntityState.Modified;

db.SaveChanges();

}

會報錯,原因和上面情況一樣,上下文中出現了主鍵一樣的多個實體,本來有一個實體了,又載入了一個主鍵一樣的實體,就報錯了。

 

用上述方法解決試試看

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };           

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity1);

entry.CurrentValues.SetValues(entity);

db.SaveChanges();

}

沒有報錯,成功更新數據,但是問題是全部數據都被更新,不是我們指定的數據更新

結果數據:

 

嘗試使用指定屬性更新:

結果你會發現數據沒有發生任何變化,原因是entry.State = EntityState.Unchanged;把ntry.CurrentValues.SetValues(entity);改變得值有還原回去了。

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };           

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity1);

entry.CurrentValues.SetValues(entity);

entry.State = EntityState.Unchanged;

entry.Property("Text").IsModified = true;

db.SaveChanges();

}

解決上述問題:

如果要解決上述問題應該使用ObjectContext的ObjectStateEntry設置當前值,狀態,以及指定修改的屬性

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };           

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext;

ObjectStateEntry entry = objectContext.ObjectStateManager.GetObjectStateEntry(entity1);

entry.ApplyCurrentValues(entity);

entry.ChangeState(EntityState.Unchanged);

entry.SetModifiedProperty("Text");

db.SaveChanges();

}

結果數據:

 

對上上述更新方式做一個封裝

public static class Test

{

//指定更新

public static void Update<TEntity>(this DbContext dbcontext,

Expression<Func<TEntity, object>> propertyExpression,

params TEntity[] entities) where TEntity : EntityBase

{

if (propertyExpression == null)

{

throw new ArgumentException("propertyExpression");

}

if (entities == null)

{

throw new ArgumentException("entities");

}

ReadOnlyCollection<MemberInfo> memberInfos = ((dynamic)propertyExpression.Body).Members;

foreach (TEntity entity in entities)

{

try

{

DbEntityEntry<TEntity> entry = dbcontext.Entry(entity);

entry.State = EntityState.Unchanged;

foreach (var memberInfo in memberInfos)

{

entry.Property(memberInfo.Name).IsModified = true;

}

}

catch

{

TEntity originalEntity = dbcontext.Set<TEntity>().Single(m => m.Id == entity.Id);

ObjectContext objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext;

ObjectStateEntry objectEntry = objectContext.ObjectStateManager.GetObjectStateEntry(originalEntity);

objectEntry.ApplyCurrentValues(entity);

objectEntry.ChangeState(EntityState.Unchanged);

foreach (var memberInfo in memberInfos)

{

objectEntry.SetModifiedProperty(memberInfo.Name);

}

}

}

}

//提交保存

public static int SaveChanges(this DbContext dbContext, bool validateOnSaveEnabled)

{

bool isReturn = dbContext.Configuration.ValidateOnSaveEnabled != validateOnSaveEnabled;

try

{

dbContext.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabled;

return dbContext.SaveChanges();

}

finally

{

if (isReturn)

{

dbContext.Configuration.ValidateOnSaveEnabled = !validateOnSaveEnabled;

}

}

}

//全部更新

public static void Update1<TEntity>(this DbContext dbContext, params TEntity[] entities) where TEntity : EntityBase

{

if (dbContext == null) throw new ArgumentException("dbContext");

if (entities == null) throw new ArgumentException("entities");

foreach(TEntity entity in entities)

{

DbSet<TEntity> dbSet = dbContext.Set<TEntity>();

try

{

DbEntityEntry<TEntity> entry = dbContext.Entry(entity);

if (entry.State == EntityState.Detached)

{

entry.State = EntityState.Modified;

}

}

catch

{

TEntity oldEntity = dbSet.Find(entity.Id);

dbContext.Entry(oldEntity).CurrentValues.SetValues(entity);

}

}

}

}

public class EntityBase

{

public int Id { get; set; }

}

public class Three : EntityBase

{

public string Text { get; set; }

public string Uu { get; set; }

}

封裝後的使用實例:

pplicationDbContext.Three entity= new ApplicationDbContext.Three() { Id = 1, Text = "update" };           

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Three entity1 = db.Threes.Single(m => m.Text == "90");

db.Update<ApplicationDbContext.Three>(m => new { m.Text }, entity);

db.SaveChanges();

}

至此更新部分已經全部完畢

Ps:其實擴展方法update有個坑,就是一但出現併發時就會報錯走catch,而其實不是想要的結果,這是個忽略的地方,併發應該拋出錯誤,用catch是忽略了併發的情況...額...

二、添加數據

簡單明瞭沒有啥好說的

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Text = "我哦哦哦" };           

using (var db = new ApplicationDbContext())

{

db.Threes.Add(entity);

db.SaveChanges();

}

數據圖:

 

三、刪除數據

簡單明瞭沒啥好說的

通過Attach把實體載入到上下文,關鍵點就是實體要存在於上下文中

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id=2 };           

using (var db = new ApplicationDbContext())

{

db.Threes.Attach(entity);

db.Threes.Remove(entity);

db.SaveChanges();

}

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id = 3 };     

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Deleted;

db.SaveChanges();

}

四、查詢

1、簡單查詢

int[] scores = { 90, 71, 82, 93, 75, 82 };

 

IEnumerable<int> scoreQuery =

from score in scores

where score > 80

orderby score descending

select score;

 

foreach (int testScore in scoreQuery)

{

Console.WriteLine(testScore);

}

//輸出結果:93 90 82 82

2、分組查詢

var queryLastNames =

from student in students

group student by student.LastName into newGroup

orderby newGroup.Key

select newGroup;

3、內聯查詢

var query = from person in people

join pet in pets on person equals pet.Owner

select new { OwnerName = person.FirstName, PetName = pet.Name };

4、分組連接

結果是:一個名字對應一個集合

var query = from person in people

join pet in pets on person equals pet.Owner into gj

select new { OwnerName = person.FirstName, Pets = gj };

5、外聯查詢

var query = from person in people

join pet in pets on person equals pet.Owner into gj

from subpet in gj.DefaultIfEmpty()

select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };

6、在查詢中處理null

var query1 =

from c in categories

where c != null

join p in products on c.ID equals

(p == null ? null : p.CategoryID)

select new { Category = c.Name, Name = p.Name };

 

var query =

from o in db.Orders

join e in db.Employees

on o.EmployeeID equals (int?)e.EmployeeID

select new { o.OrderID, e.FirstName };

7、在查詢中處理異常

IEnumerable<int> dataSource;

try

{

dataSource = GetData();

}

catch (InvalidOperationException)

{

Console.WriteLine("Invalid operation");

goto Exit;

}

var query = from i in dataSource

select i * i;

foreach (var i in query)

Console.WriteLine(i.ToString());

Exit:

Console.WriteLine("Press any key to exit");

 

string[] files = { "fileA.txt", "fileB.txt", "fileC.txt" };

var exceptionDemoQuery =

from file in files

let n = SomeMethodThatMightThrow(file)

select n;

try

{

foreach (var item in exceptionDemoQuery)

{

Console.WriteLine("Processing {0}", item);

}

catch (InvalidOperationException e)

{

Console.WriteLine(e.Message);

}

更多關於查詢請查考MSDN,裡面很詳細

https://msdn.microsoft.com/zh-cn/library/bb384065.aspx

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.0啟用開發者模式 ①填寫伺服器配置: 啟用開發模式需要先成為開發者,而且編輯模式和開發模式只能選擇一個(進入微信公眾平臺=>開發=>基本配置)就可以看到以下的界面: 點擊修改配置,會出現以下界面: 填寫伺服器地址(URL)、Token和EncodingAESKey,其中URL是開發者用來接收微信
  • 最近看到不少介紹微軟ASP.NET Identity技術的文章,但感覺都不夠完整深入,本人又恰好曾在Adam Freeman所著的《Pro ASP.NET MVC Platform》一書中看到過有關ASP.NET Identity的完整介紹,為此特將有關章節翻譯出來,希望需要瞭解此項技術的園友能從中...
  • 在開發XX新聞的過程中,UI部分使用了Master/Detail(大綱/細節)佈局樣式。Win10系統中的郵件App就是這種樣式,左側一個列表,右側是詳情頁面。關於這種 樣式的說明可參看MSDN文檔:https://msdn.microsoft.com/zh-cn/library/windows/a
  • 今天上傳附件出現了下圖所示的問題: 查找百度發現http://www.cnblogs.com/chuncn/archive/2009/09/08/1562759.html 文中提的比較靠譜。 但是,設置後還是不對。後來發現iis不能用localhost訪問,增加所有網站綁定都能訪問後解決。如下圖:
  • 使用SmtpClient發送Email時,我們可以創建ISmtpClient介面和SmtpClientWrapper適配類,在單元測試中對ISmtpClient進行Mock或自定義FackeSmtpClient,但nDumbster的Facke SMTP Server給我們提供了更直觀更簡單的方式進
  • 最近在做微信開發時用到了一些json的問題,就是把微信返回回來的一些json數據做一些處理,但是之前json掌握的不好,浪費了好多時間在查找一些json有關的轉換問題,我所知道的方法只有把json序列化和反序列化一下,但是太麻煩了我覺得,所以就在找一些更簡單又方便使用的方法。也許這個會有用吧,所以先
  • ASP.NET 上下文對象 ASP.NET 提供了一系列對象用來給當前請求,將要返回到客戶端的響應,以及 Web 應用本身提供上下文信息。間接的,這些上下文對象也可以用來回去核心 ASP.NET 框架特性。 上下文對象提供了應用,當前請求,與當前請求相關聯的響應的信息。也提供了對多數重要的 ASP.
  • 註:本文是【ASP.NET Identity系列教程】的第二篇。本系列教程詳細、完整、深入地介紹了微軟的ASP.NET Identity技術,描述瞭如何運用ASP.NET Identity實現應用程式的用戶管理,以及實現應用程式的認證與授權等相關技術,譯者希望本系列教程能成為掌握ASP.NET Id
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...