開發筆記:基於EntityFramework.Extended用EF實現指定欄位的更新
今天在將一個專案中使用儲存過程的遺留程式碼遷移至新的架構時,遇到了一個問題——如何用EF實現資料庫中指定欄位的更新(根據UserId更新Users表中的FaceUrl與AvatarUrl欄位)?
原先呼叫儲存過程的程式碼:
public bool UpdateAvatar(Guid userId, string faceUrl, string avatarUrl) { DbCommand command = _db.GetStoredProcCommand("User_UpdateFaceAvatar"); _db.AddInParameter(command,"@FaceUrl", DbType.String, faceUrl); _db.AddInParameter(command, "@AvatarUrl", DbType.String, avatarUrl); _db.AddInParameter(command, "@UserId", userId); return _db.ExecuteNonQuery(command) > 0; }
儲存過程中所使用的SQL語句:
UPDATE Users SET FaceUrl=@FaceUrl,AvatarUrl=@AvatarUrl WHERE[UserId]=@UserId
在新的架構中,資料庫訪問用的是Entity Framework,並且用IUnitOfWork介面進行了封裝,Application層對資料庫的操作是通過IUnitOfWork介面完成的。
IUnitOfWork介面是這麼定義的:
public interface IUnitOfWork : IDisposable { IQueryable<T> Set<T>() where T : class; T Add<T>(T entity) where T : class; IEnumerable<T> AddRange<T>(IEnumerable<T> entities) where T : class; T Attach<T>(T entity) where T : class; T Remove<T>(T entity) where T : class; IEnumerable<T> RemoveRange<T>(IEnumerable<T> entities) where T : class; bool Commit(); Task<bool> CommitAsync(); }
如果不給IUnitOfWork新增新的介面方法,可以使用EF的change tracking完成指定欄位的更新操作。
Application.Services中的實現程式碼:
public async Task<bool> UpdateFaceAvatar(Guid userId, string faceUrl, string avatarUrl) { var user = await _userRepository.GetByUserId(userId); user.FaceUrl = faceUrl; user.AvatarUrl = avatarUrl; return await _unitOfWork.CommitAsync(); }
使用ef change tracking的優點是如果屬性的值沒有被改變,就不會觸發資料庫更新操作,缺點是每次更新前都要進行1次查詢操作。
而對於這裡的更新FaceUrl與AvatarUrl的應用場景,更新前就明確知道資料已經改變,直接更新資料庫即可。ef change tracking的更新前查詢不僅沒有必要,而且增加了額外的開銷。
於是,嘗試尋找新的解決方法。
開始嘗試的是EF的DbEntityEntry,未抽象的實現程式碼:
public class EfUnitOfWork : DbContext, IUnitOfWork { public async Task<bool> UpdateAsync(User user) { base.Set<User>().Attach(user); base.Entry<User>(user).Property(x => x.FaceUrl).IsModified = true; base.Entry<User>(user).Property(x => x.AvatarUrl).IsModified = true; return (await base.SaveChangesAsync()) > 0; } }
呼叫程式碼:
await UpdateAsync(new User { UserId = userId, FaceUrl = faceUrl, AvatarUrl = avatarUrl });
但是基於這個實現,很難抽象出一個好用的介面方法。
後來突然想到前一段時間在一個專案中用到的EntityFramework.Extended。針對Update操作,它實現了一個優雅的EF擴充套件,為何不直接用它呢?
//example of using an IQueryable as the filter for the update var users = context.Users.Where(u => u.FirstName == "firstname"); context.Users.Update(users, u => new User {FirstName = "newfirstname"});
於是,如獲珍寶地基於EntityFramework.Extended進行實現。
首先在IUnitOfWork中新增一個UpdateAsync()的介面方法:
public interface IUnitOfWork : IDisposable { Task<bool> UpdateAsync<T>(IQueryable<T> source, Expression<Func<T, T>> updateExpression) where T : class; }
然後在IUnitOfWork.UpdateAsync()的實現中,呼叫EntityFramework.Extended的UpdateAsync擴充套件方法,完成Update操作:
using EntityFramework.Extensions; public class EfUnitOfWork : DbContext, IUnitOfWork { async Task<bool> IUnitOfWork.UpdateAsync<T>(IQueryable<T> source, Expression<Func<T, T>> updateExpression) { return (await source.UpdateAsync<T>(updateExpression)) > 0; } }
隨之,Application.Services中的實現程式碼改為這樣:
public async Task<bool> UpdateFaceAvatar(Guid userId, string faceUrl, string avatarUrl) { IQueryable<User> userQuery = _userRepository.GetByUserId(userId); return await _unitOfWork.UpdateAsync<User>( userQuery, x => new User { FaceUrl = faceUrl, AvatarUrl = avatarUrl } ); }
(注:這裡的_userRepository.GetByUserId的返回型別需要改為IQueryable,再一次驗證了Repository返回IQueryable的必要性,相關博文:開發筆記:用不用UnitOfWork以及Repository返回什麼集合型別)
跑單元測試驗證一下。
單元測試程式碼:
[Fact] public async Task UpdateFaceAvatar() { var result = await _userService.UpdateFaceAvatar(userId, faceUrl, avatarUrl); Assert.True(result); }
測試結果:
1 passed, 0 failed, 0 skipped, took 11.38 seconds (xUnit.net 1.9.1 build 1600).
測試通過!
用SQL Profiler檢視一下資料庫中實際執行的SQL語句:
exec sp_executesql N'UPDATE [dbo].[Users] SET [FaceUrl] = @p__update__0, [AvatarUrl] = @p__update__1 FROM [dbo].[Users] AS j0 INNER JOIN ( SELECT 1 AS [C1], [Extent1].[UserId] AS [UserId] FROM [dbo].[Users] AS [Extent1] WHERE [Extent1].[UserId] = @p__linq__0 ) AS j1 ON (j0.[UserId] = j1.[UserId])',N'@p__linq__0 uniqueidentifier,@p__update__0 nvarchar(24),@p__update__1 nvarchar(24)', @p__linq__0='BD42420B-63CF-DD11-9E4D-001CF0CD104B',@p__update__0=N'20150810180742.png',@p__update__1=N'20150810180743.png'
就是我們期望的SQL語句。
最終驗證了,新增IUnitOfWork.UpadteAsync()介面,基於EntityFramework.Extended,用EF實現資料庫中指定欄位的更新,這種方法在實際開發中使用完全可行。
於是,又少了一個使用儲存過程的理由。
相關推薦
開發筆記:基於EntityFramework.Extended用EF實現指定欄位的更新
今天在將一個專案中使用儲存過程的遺留程式碼遷移至新的架構時,遇到了一個問題——如何用EF實現資料庫中指定欄位的更新(根據UserId更新Users表中的FaceUrl與AvatarUrl欄位)? 原先呼叫儲存過程的程式碼: public bool UpdateAvatar(Guid userId, s
sql update 用一個表的欄位更新另一個表
UPDATE a SET a.areacode=b.areacode FROM [dbo].[T_Mid_AirPoll] a ,[dbo].[T_Bas_AirStation] b WHER
資料脫敏——基於Java自定義註解實現日誌欄位脫敏
上文說了資料過敏主要有兩個思路:第一個就是在序列化實體之前先把需要脫敏的欄位進行處理,之後正常序列化;第二個就是在實體序列化的時候,對要脫敏的欄位進行處理。 脫敏實現思路 這裡探討第一種方法,用基於自定義註解的方式實現日誌脫敏。 要對
用MongoTemplate查詢指定欄位的正確奧義
這裡舉一個我個人犯的一個錯誤,希望看到此博文的人能避免犯同樣的錯誤: 在CompanyInfo這個類中,它其中包含一個List型別的AccountInfo屬性。然後好戲開始了,我希望通過BasicDB
SAP公開課筆記:基於HANA的軟體開發
第一章 通過OData暴露和消費資料的基礎架構 這章的內容很簡單。在開始真正開始開發之前,回顧了一下第一章所提到過的傳統軟體開發架構和使用XS架構的區別。值得記下來的是ICM是整個架構的一部分。 SAP internet communication manager(ICM)
開發筆記:用不用UnitOfWork以及Repository返回什麼集合型別
這2天實際開發中明確的東西,在這篇博文中記錄一下。 之前對是否需要自己封裝UnitOfWork有些猶豫,因為Entity Framework就是一個UnitOfWork實現, 自己再封裝一下顯得有些多餘。 但是在這次開發中,把涉及資料庫操作的實現程式碼放在最後寫,先完成其他層的程式碼。這種情況下,根本用不
張高興的 Windows 10 IoT 開發筆記:使用 ULN2003A 控制步進電機
uln2003 zhang windows iot ges 開發 ima dem win GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/ULN2003A 張高興的 Wind
張高興的 Windows 10 IoT 開發筆記:三軸數字羅盤 HMC5883L
cnblogs -i mas https http png 開發 target 分享 註意,數據不包含校驗,準確的來說我不知道怎麽校驗,但方向看起來差不多是對的。。。 GitHub:https://github.com/ZhangGaoxing/windows-io
張高興的 Xamarin.Forms 開發筆記:為 Android 與 iOS 引入 UWP 風格的漢堡菜單 ( MasterDetailPage )
操作 using eat stp 取消 height 新建 屬性 turn 所謂 UWP 樣式的漢堡菜單,我曾在“張高興的 UWP 開發筆記:漢堡菜單進階”裏說過,也就是使用 Segoe MDL2 Assets 字體作為左側 Icon,並且左側使用填充顏色的矩形用來表示
張高興的 Windows 10 IoT 開發筆記:BMP180 氣壓傳感器
bsp git left margin 氣壓 play 氣壓傳感器 分享 get 原文:張高興的 Windows 10 IoT 開發筆記:BMP180 氣壓傳感器 註意:海拔高度僅供參考 GitHub : https://github.com/ZhangGaoxin
張高興的 Windows 10 IoT 開發筆記:使用 MAX7219 驅動 8×8 點陣
.com 使用 window win get mas image href git 原文:張高興的 Windows 10 IoT 開發筆記:使用 MAX7219 驅動 8×8 點陣 GitHub:https://github.com/ZhangGaoxing/w
張高興的 Windows 10 IoT 開發筆記:DHT11 溫濕度傳感器
分享 lock spl .com play ima image log win 原文:張高興的 Windows 10 IoT 開發筆記:DHT11 溫濕度傳感器 GitHub : https://github.com/ZhangGaoxing/windows-iot-de
張高興的 Windows 10 IoT 開發筆記:ToF Sensor VL53L0X
mar 分享 demo isp 技術 ref windows ges mas GitHub : https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/VL53L0X 張高興的 Windows 10 Io
張高興的 Windows 10 IoT 開發筆記:紅外溫度傳感器 MLX90614
ima master lock right win hang tps iot pla GitHub : https://github.com/ZhangGaoxing/windows-iot-demo/tree/master/MLX90614 張高興的 Windows
張高興的 Windows 10 IoT 開發筆記:使用 Lightning 中的軟件 PWM 驅動 RGB LED
pic pwm 原生 感覺 發現 rgb rgb led ace light 感覺又幫 Windows 10 IoT 開荒了,所以呢,正兒八經的寫篇博客吧。其實大概半年前就想寫的,那時候想做個基於 Windows 10 IoT 的小車,但樹莓派原生不支持 PWM 啊。百度也
android開發筆記:MainActivity.java與activity_main.xml
https://www.jianshu.com/p/f5e56fb2f215 剛開始開發android的時候,新建一個activity總是會新建兩個檔案,我們已預設命名MainActivity.java與activity_main.xml兩個檔案來給大家介紹。 activity
開發實戰:基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統(二)
基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統 繼上一篇 [專案需求分析](https://blog.csdn.net/ITBigGod/article/details/82729233)之後,接下來就是資料庫設計了。 作為一個管理系統,各種資訊表是必
開發實戰:基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統(一)
基於深度學習+maven+SSM+EasyUI的高校共享汽車管理系統 1.專案簡介 在現在,共享汽車在中國各地方開始熱起來,於是本人想做一個基於maven+SSM+EasyUI的高校共享汽車管理系統,當然該專案是博主本人2019年的畢業設計,除了javaweb部分,本專案還
Linux應用程式開發筆記:測試程式碼執行時間
#include <stdio.h> #include <sys/times.h> #include <unistd.h> void main(void) { double duration; clock_t start,
Linux應用程式開發筆記:make menuconfig環境搭建
1、目的 Linux應用程式開發採用與Linux核心一致的menuconfig圖形配置,方便功能元件裁剪。 2、準備工作 下載:Kconfiglib原始碼(https://github.com/ulfalizer/Kconfiglib) 3、環境搭