EntityFramework Add方法與Attach區別

   一 先發問。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,
    }
View Code

  這五種狀態分別是: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上下文

相關文章
相關標籤/搜索