一 先发问。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上下文;