一 先發問。html
問題:在使用EF過程當中,可否有一個方法能夠直接執行傳入的SQL語句。糾結的只找到了調用存儲過程的方法,難道要SqlHelper.cs?數據庫
二 友情提示ide
本文內容參考自MSDN。
性能
三 言歸正傳this
平時使用MVC 開發時,在CRUD相關的Action當中,都會有在最後調用一句代碼:spa
db.SaveChanges();// Entities db=new Entities()
這個方法會根據當前欲操做的實體(Entity)所處的狀態(State)與數據庫交互。單單從名字上能夠看出這個方法是爲了「保存改變」,在現實中,一位你很久沒見的朋友有可能會這樣說:「小王啊,很久沒見,你變胖了,是否是賺大錢了,生活安逸嘍?」姑且不論你是否是張的長胖了,仍是賺大錢了,這裏面「胖」就是用來表徵你當前所處的情況的一個描述。在命名空間System.Data當中,也有一個描述實體所處狀態的枚舉類型EntityState:翻譯
// 摘要: // 實體對象的狀態。 [Flags] public enum EntityState { // 摘要: // 對象存在,但未由對象服務跟蹤。在建立實體以後、但將其添加到對象上下文以前,該實體處於此狀態。經過調用 System.Data.Objects.ObjectContext.Detach(System.Object) // 方法從上下文中移除實體後,或者使用 System.Data.Objects.MergeOption.NoTrackingSystem.Data.Objects.MergeOption // 加載實體後,該實體也會處於此狀態。 Detached = 1, // // 摘要: // 自對象加載到上下文中後,或自上次調用 System.Data.Objects.ObjectContext.SaveChanges() 方法後,此對象還沒有通過修改。 Unchanged = 2, // // 摘要: // 對象已添加到對象上下文,但還沒有調用 System.Data.Objects.ObjectContext.SaveChanges() 方法。對象是經過調用 // System.Data.Objects.ObjectContext.AddObject(System.String,System.Object) // 方法添加到對象上下文中的。 Added = 4, // // 摘要: // 使用 System.Data.Objects.ObjectContext.DeleteObject(System.Object) 方法從對象上下文中刪除了對象。 Deleted = 8, // // 摘要: // 對象已更改,但還沒有調用 System.Data.Objects.ObjectContext.SaveChanges() 方法。 Modified = 16, }
這五種狀態分別是:Detached-遊離;UnChanged-沒有變化;Added-添加;Deleted-刪除;Modified-編輯。Detached狀態下的Entity不會被上下文(context)所捕獲(track),好比說下面這種狀況下:code
public JsonResult Edit(UserModel source) { if (this.ModelState.IsValid) { User destination = new User(); UserToEntity(source, destination); destination.ID = source.ID; db.Entry(destination).State = System.Data.EntityState.Modified; db.SaveChanges(); return Json(new { isok = true, tip = "修改爲功" }); } else { return Json(new { isok = false, tip = "添加用戶失敗" }); } }
在db.Entry(destination)……這句代碼執行以前,destination的State狀態就是遊離。htm
除了遊離狀態,剩下的四種狀態均會被上下文所捕獲,具體意思也很好理解。對象
當SavaChanged()方法執行期間,他會查看當前Entity的EntityState的值,決定是去新增(Added)、修改(Modified)、刪除(Deleted)、什麼也不作(UnChanged)。
回到正題,DbContext類的Add()方法的做用就是將一個Entity的State修改成Added,這樣在SavaChanged()方法就會將實體新增到數據庫當中。而Attach在 微軟的中文翻譯中是附加,不一樣於Add方法的添加,她是將一個處於Detached的Entity附加到上下文,而附加到上下文後的這一Entity的State爲UnChanged,因此在下面的代碼中,須要將obj的State修改成Modified:
/// <summary> /// 更新Entity(注意這裏使用的傻瓜式更新,可能性能略低) /// </summary> /// <param name="model"></param> /// <returns></returns> public virtual bool Update(T entity) { var obj = db.Set<T>();//新建一個泛型DbSet obj.Attach(entity);//附加到上下文 db.Entry(entity).State = System.Data.EntityState.Modified;//修改State return db.SaveChanges() > 0; }
新建的obj Entity由於出於Detached,因此咱們須要先附加後修改其EntityState;
搞清楚這點,完成添加功能的Action 是否是能夠這樣寫呢:
public virtual bool Add(T entity) { var obj = db.Set<T>(); obj.Attach(entity); db.Entry(entity).State = System.Data.EntityState.Added; return db.SaveChanges() > 0; }
一樣的,刪除的Remove方法也能夠不用,轉而修改其State爲Deleted。
最後,那就能夠用Action完成Add或Update的功能:
public void InsertOrUpdate(Blog blog) { using (var context = new BloggingContext()) { context.Entry(blog).State = blog.BlogId == 0 ? EntityState.Added : EntityState.Modified; context.SaveChanges(); } }
以往增長刪除都是用一個相同的部分視圖加上不一樣的控制器實現,如今只須要在一個控制器就能實現增長和修改了。
四 Context
上下文是一個不太好描述清楚的東東,我是這樣簡單理解的:有一些方法,在參數中不方便,也不可能獲取到的東東(請原諒我這樣形容),就能夠將其存儲在上下文中。好比我這個方法須要知道當前用戶是誰,須要知道此次請求來自於哪個Controller,就能夠調用不一樣的Context得到。在MVC中有不少上下文類,列如這篇博文總結的MVC上下文;