1. 程式人生 > 其它 >EF操作_使用實體修改資料庫的使用者資訊

EF操作_使用實體修改資料庫的使用者資訊

使用EF執行更新操作

方法1,寫sql語句

//例項化實體
FHZMEntities fHZMEntities = new FHZMEntities();
//引數化列表
List<SqlParameter> sqlParameterList = new List<SqlParameter>() { 
    new SqlParameter("@UserName",userInfo.UserName),
    new SqlParameter("@Number",userInfo.Number),
    new SqlParameter("@UClass",userInfo.UClass),
    new SqlParameter("@Ustate",userInfo.Ustate),
    new SqlParameter("@Id",userInfo.Id),
};
//給實體新增sql語句並操作資料庫,第二個引數是一陣列,如果只是一個引數化物件就可以不是陣列,但是如果是引數化物件集合就要轉為陣列,不然報錯
int count = fHZMEntities.Database.ExecuteSqlCommand("update UserInfo set UserName=@UserName,Number=@Number,UClass=@UClass,Ustate=@Ustate where Id=@Id", sqlParameterList.ToArray());
//返回受影響的行數
return Json(count);


方法2:先查詢再更新

這種修改方式比較通用,優點,實體只改資料庫裡需要修改的欄位,不會全部修改,
缺點,它會先查詢,會浪費一點效率,而且如果一個表單裡有大量欄位需要修改,這樣把要修改的欄位全部寫出來賦值比較麻煩
查詢需要用到id來查,直接修改則不需要,只需要傳id即可,框架會自動從資料庫里根據你傳的id來操作需要修改的資訊

//例項化實體
FHZMEntities fHZMEntities = new FHZMEntities();
//執行實體操作,從資料庫查詢相應的資料,
UserInfo NewUserInfo = fHZMEntities.UserInfo.Where(a =&gt; a.Id == userInfo.Id).FirstOrDefault();
//更改需要更新的資訊
NewUserInfo.UserName = userInfo.UserName;
NewUserInfo.Number = userInfo.Number;
NewUserInfo.UClass = userInfo.UClass;
NewUserInfo.Ustate = userInfo.Ustate;
//對資料庫執行操作
int count = fHZMEntities.SaveChanges();
//設定可以接收get請求return Json(1, JsonRequestBehavior.AllowGet);
//返回給ajax受影響的行數
return Json(count);

方法3:不查詢直接修改

優點:如果有大量要修改的欄位,它也只需要將物件新增到實體的更新請求,不需要一個一個欄位修改,
改全部欄位非常方便,因為不用把欄位依次寫出來,直接把物件給實體即可。
缺點:每一次都會將實體物件裡的所有欄位全部修改,因為它是將實體物件直接給模型,不能指定修改屬性
查詢需要用到id來查,直接修改則不需要,只需要傳id即可,框架會自動從資料庫里根據你傳的id來操作需要修改的資訊

//例項化實體
FHZMEntities fHZMEntities = new FHZMEntities();
//給實體新增一個修改的狀態(他會認為實體物件所有欄位都會修改,就是它是改全部)
fHZMEntities.Entry(userInfo).State = System.Data.EntityState.Modified;
//呼叫SaveChanges執行新增的狀態
int count = fHZMEntities.SaveChanges();
//返回受影響的行數
return Json(count);

這種修改方式有種不好的地方,它是覆蓋式修改,就是將要修改的物件的紀錄裡的每個欄位全部修改,如果你有傳值還好說,沒有傳值你不想改的欄位就會預設被修改為空,如圖:

如圖:你不想修改使用者的Hobby和gender欄位的值,所以前臺就沒有傳這兩個值過來,所以傳過來的物件裡這兩個欄位的值是為空的

資料庫中也可以看到沒修改前的樣子:

但是修改之後就可以看到,由於你沒有傳這兩個值過來,所以資料庫裡這兩個值被修改為空了。

這就是這個方法的弊端,雖然可以不用依次賦值,但是卻不能修改指定欄位,這個方法適用於修改表單的全部資料時使用,也就是要修改一個物件裡的所有欄位的時候很方便,不用像上一個方法一樣依次賦值。


方法4:不需要查詢,而且可以修改指定欄位

這種寫法和方法1類似,只不過方法1需要對要修改的欄位賦值,而這種寫法它結合第二種的寫法,都是把值全部帶到資料庫,只不過
是對要修改的的欄位改為true,這樣就可以對它不賦值了,不像方法一那樣麻煩,而且還不用查詢一次,可以利用這個原理自己寫一個方法,這樣就可以不用一個一個把要修改的欄位寫出來了。

//例項化實體
FHZMEntities fHZMEntities = new FHZMEntities();
//把物件新增到上下文中
fHZMEntities.UserInfo.Attach(userInfo);
//獲取指定的實體
var entry = fHZMEntities.Entry(userInfo);
//設定請求資料庫後可以修改的欄位
entry.Property("UserName").IsModified =true;
entry.Property("Number").IsModified = true;
entry.Property("UClass").IsModified = true;
entry.Property("Ustate").IsModified = true;
//資料庫裡除了上面幾個欄位都不能修改
////fHZMEntities.Entry(userInfo).Property("usernae").IsModified = true;,上面兩個步驟可以這樣簡寫
//呼叫執行實體的請求操作資料庫的方法
int count=fHZMEntities.SaveChanges();
//返回受影響的行數
return Json(count);

上面的指定要修改的欄位的書寫可以這樣寫

最後,使用這種方法對方法3的缺點進行同樣的測試:測試結果如下圖,發現即使不傳gender和Hobby這兩個欄位時,它也不會去修改資料庫裡的這兩個欄位。


方法5:自己通過反射+泛型實現通用的修改方法

這玩意兒以後學了反射再來寫,這個方法可以放方法4更加簡便


練習

單擊表格裡的更新,開啟一個彈窗,在這個彈窗裡可以修改使用者的資訊,點選確定之後提交到指定的控制器,在控制器裡完成EF操作。

第一步:建一個隱藏元素,用於彈窗的內容:

彈窗的型別和正文修改好

第三步:只需要給表格裡的修改的單擊事件前把彈窗裡的內容裡的值賦值好,這樣彈窗一開啟裡面就有使用者的資訊了

上面這張圖裡的做法並不優雅,因為是要對彈窗裡的內容賦值,但是彈窗又是以頁面的形式開啟的,而且彈窗裡的內容其實就是頁面裡的一個隱藏域,所以在單擊事件執行時候賦值也是科學的,只是不優雅,其實,layer自己有一個載入事件,這個事件執行完了才打開彈窗,所以也可以在layer的載入事件裡給這個頁面的隱藏域賦值,如下圖:

第四步,在彈窗裡的yes的函式裡寫你訪問控制器的方式,使用ajax和使用location.href形式都行,都是為了傳值給控制器。
控制器只需要接受傳過來的使用者資訊物件,然後讓EF執行操作資料庫修改即可。
如下圖:控制器的引數:

所以你傳的值也得按照這個物件裡的屬性名來傳,不然控制器裡的引數這個物件可能某些欄位的值為空,傳值格式如下圖:

控制器處理完後使用ajax的形式不希望重新整理頁面來實現前臺資料的更新的話,因為前臺的資料都是網頁載入時控制器裡EF訪問資料庫時拿到的資料給前臺的,如果改了值要使前臺表格裡的值實時更新的話,重新重新整理頁面即可,但是重新整理頁面使用者體驗不好,所以也可以通過ajax的回撥函式裡使用js修改當前行的資料即可。


練習2

這個練習和上面那個練習一樣,只不過這次將layer的內容改為別的檢視也就是將別的一個單獨的網頁作為它的內容。

第一步

下圖就是被用作layer的內容的網頁

第二步

設定layer的型別和路徑即可讓彈窗的內容為你指定的網頁

第三步

至於你開啟彈窗時裡面的值怎麼賦過去,方式有下面幾種,:

第一種:

可以直接傳個你點選的那個使用者的id給控制器,控制器使用EF的實體查當前使用者的資料,如下:
傳使用者的id給控制器:

第二步:控制器通過傳過來的id通過實體查出這個使用者的資訊,並傳給前臺

第三步:前臺裡使用控制器傳來的使用者資料即可

這種方法不是很好,因為它還要重新從資料庫裡查詢使用者資訊。接下來第二種方法:


第二種

直接把使用者資訊傳過來
第一步:在被當做iframe層的頁面(子頁面)裡用js寫一個方法,便於外面這個頁面(父頁面)開啟彈窗時呼叫,這個方法作用相當於接收傳過來的引數並對這個頁面裡的文字框賦值,如圖::

第二步:外面層在彈窗的載入事件裡呼叫並傳引數給這個方法

頁面層呼叫iframe裡的方法就是:
window.frames[frames層的id].方法名
預設frames每次用到frames層的時候瀏覽器會預設給frames元素取id和name,這兩個都是一樣的,預設都是”layui-layer-iframe”開頭,至於最後的iframe是幾就看你開啟的是第幾次了,
frame的name和id測試:

第一次開啟:
第二次開啟:

可以看到每次的id的最後的數字都會變,但是我們可以直接用layer的載入事件裡的第二個引數來搞定這個問題,如果你iframe的名字寫錯就調不了你iframe裡的方法了。

如下圖為解決方法:

這裡順便提一下子頁面iframe層呼叫外面頁面(父頁面)的方法的格式:
parent.方法名();

第四步

在修改完畢後點擊確定,呼叫子頁面的方法,使子頁面(iframe層)完成更新,訪問控制器,控制器使用EF實體操作資料庫

方式1

提交給資料庫後不想重新整理前臺頁面實現更新,而使用ajax非同步重新整理:
在yes的事件裡呼叫子頁面更新前臺資料的方法,把要修改的id和當前使用者所在的行傳給子頁面

子頁面的方法:這個方法就是在子頁面裡修改父頁面的表格裡的資料,並沒有通過重新整理的方式更新前臺的表格裡的資料。

方式2

重新整理式更新前臺資料:
這種方式簡單,在前臺重新整理,也就是子頁面層的儲存的方法裡的ajax的回撥函式裡返回受影響的行數,前臺的回撥函式裡判斷重新整理即可

子頁面的儲存方法:

這裡有個坑,一定要將ajax改為同步,不然前臺接收到的返回值永遠為0,因為是非同步的話,它不好去暫停等ajax執行完畢後對count賦值,也就是還沒有等ajax執行完,程式就已經執行完了return了,這樣前臺永遠都不會重新整理。
也可以不使用ajax,可以直接使用lacation.href,把值傳過去,在控制器裡判斷是否重新整理等,但是這樣寫更麻煩,因為location現在我不知道怎麼接收返回值,所以不管EF是否執行成功這個彈窗裡的內容都會變為那個控制器的檢視,如果控制器沒對應的檢視還會報錯,所以目前推薦使用ajax訪問控制器,控制器返回受影響的行數這樣寫

父頁面的回撥函式重新整理即可:

這裡還有一個坑,為什麼要把重新整理放在前臺呢,直接放在子頁面(iframe)裡重新整理不香嗎,
其實我們可以測試,如果直接放在子頁面裡,它會重新整理子頁面訪問父頁面,彈窗裡就顯示父頁面了,因為彈窗還沒有關,如下測試:

將子頁面裡的ajax回撥函式裡寫判斷重新整理:

但是當我們在彈窗裡點確定之後:它把內容顯示在彈窗裡了。

這種方法的總結:呼叫frames頁面的方法,並把要修改的Id傳過去,要接收返回值,根據返回值來判斷是否重新整理頁面,不推薦使用這種方法,麻煩,而且邏輯放在leyer的子頁面裡就好了,讓它處理,這個頁面只需要負責開啟彈窗,並傳值過去即可

方式3(推薦使用)

在呼叫iframe的方法時傳一個方法過去,讓iframe的ajax的回撥函式裡執行即可,

子頁面裡接收這個方法,回撥函式裡執行

這樣寫還不用考慮非同步同步的問題,因為根本不需要返回值回去,ajax執行完了會自動執行重新整理頁面的方法


練習3,批量更新

練習3和前面的邏輯一樣,只不過點選的時候可以批量在文字框裡修改多個使用者的資訊

步驟一
直接將選中的複選框的行改為編輯狀態

這裡第六個td可以複製上面篩選裡的下拉列表框,減少程式碼

步驟二,儲存
思路,前臺接收所有修改的使用者資訊,將每個使用者資訊都單獨存在一個物件裡,然後再把這個使用者物件放入一個存所有使用者物件的數組裡,然後序列化為json陣列字串傳給控制器。

步驟三,控制器接收並反序列化

步驟四,迴圈新增狀態,一次提交,使EF只操作一次資料庫,避免迴圈操作資料庫浪費效率,