时间:2021-07-01 10:21:17 帮助过:2人阅读
2. DbDatabase.SqlQuery 没有跟踪状态的查询
3. DbDatabase.SqlCommand 直接执行SQL语句 一般用来 批量 增删改
下面 让我们来看下使用方法
再上篇的公共资源库里 添加方法
public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters) { return dbSet.SqlQuery(query, parameters); } public virtual IEnumerable<TEntity> GetwhithdbSql(string query, params object[] parameters) { return context.Database.SqlQuery<TEntity>(query, parameters); }View Code
通过对比 来介绍下 第一个和第二个的区别~~
在课程控制器下 分别执行这两个方法
var query = "SELECT * FROM Course WHERE CourseID = @p0"; Course course = unitofwork.CourseRepository.GetWithRawSql(query,id).Single(); EntityState state = unitofwork.GetState(course); string name=course.Department.Name; Course coursetwo = unitofwork.CourseRepository.GetwhithdbSql(query, id).Single(); EntityState statetwo = unitofwork.GetState(coursetwo); string nametwo = coursetwo.Department.Name;View Code
执行后的结果
1.先来看第一个 他的状态是unchanged 也就说 他加入了context上下文中 有跟踪状态

并且下面顺利读取出course.Department.Name 也就是可以读取到导航属性
2.再看来看第二个 他的状态是detached 并没有加入到 context上下文中 没有有跟踪状态

所以 我们下面的读取导航属性的内容时 会报错~~
3.再来说说DbDatabase.SqlCommand 这个比较简单 增删改用这个不错 下面说个批量更新的例子~
假设有需求 更新所有的课程学分为N时 在这种批量操作时 用ORM 框架 就会不太方便了 这时我们可以用这个直接执行SQL语句
这个业务属于课程的 所以继承通用资源库类 代码如下
using System; using ContosoUniversity.Models; namespace ContosoUniversity.DAL { public class CourseRepository : GenericRepository<Course> { public CourseRepository(SchoolContext context) : base(context) { } public int UpdateCourseCredits(int multiplier) { return context.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier); } } }View Code
修改上篇的UnitOfWork类
private CourseRepository courseRepository; public CourseRepository CourseRepository { get { if (this.courseRepository == null) { this.courseRepository = new CourseRepository(context); } return courseRepository; } }View Code
控制器如下
public ActionResult UpdateCourseCredits(int? multiplier) { if (multiplier != null) { ViewBag.RowsAffected = unitOfWork.CourseRepository.UpdateCourseCredits(multiplier.Value); } return View(); }View Code
最后添加视图~~
运行结果图

二.无跟踪查询
EF再默认的时候给我们开启了跟踪查询 这个跟踪的是什么呢? 先来介绍下这个 看下面的代码
Department duplicateDepartment = db.Departments .Where(d => d.InstructorID == department.InstructorID) .FirstOrDefault(); duplicateDepartment.Name = "wuhawuha"; bool IsUpdate=db.Entry<Department>(duplicateDepartment).Property(p => p.Name).IsModified; //是否修改 string now= db.Entry<Department>(duplicateDepartment).Property(p => p.Name).CurrentValue; //现在的值 string before = db.Entry<Department>(duplicateDepartment).Property(p => p.Name).OriginalValue; //以前的值View Code
我们先随便查出一个院系信息 修改他的名字 这是我们会通过上面的信息 得到现在的值 以前的值 这就是跟踪帮我们做的事 下面看下无跟踪的

实现无跟踪很简单 在查询时 加上asNoTracking() 即可. 加上后我们发现 明明发生变化了 但是IsUpdate依然为false。而且在 获取以前的值时 抛出了异常。
通常情况 我们并不需要跟踪这些状态 可以在查询时去掉跟踪查询,可以使得性能 得到提升~ 以前一直觉得去掉这个会影响导航属性的使用 但是测试后 并没有影响~
这个跟踪查询 还会带来另一个问题 看下面的图

这是在修改前 加了句 先查询这个修改的 再修改 这是就会报错 ObjectStateManager 中已存在具有同一键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。
遇到这个错误 在查询时 加上asNoTracking() 即可. 目前在用EF时 个人并不喜欢有跟踪状态~~ 喜欢加上asNoTracking()
三.使用代理
了解过ORM框架的 我们知道 导航属性 使用了代理模式 ,这个代理 也是跟导航属性有关的 。 禁用代理 可以提高序列化的速度 .
关闭代理的代码为在继承 dbcontext 的类里 加上如下代码
public SchoolContext() { this.Configuration.ProxyCreationEnabled = false; }
下面展示下有代理和没有代理的区别 先看有代理时

我们的Administrator 是导航属性 我们看到 得到的是一串很长的数字和字母的组合 在下面 访问这个Administrator属性时 会通过延迟加载 才得到Administrator属性
再来看代理关闭时的图

看我们的导航属性 都为null 不能正确获得导航属性
四.自动检测功能
DbSet.FindDbSet.LocalDbSet.RemoveDbSet.AddDbSet.AttachDbContext.SaveChangesDbContext.GetValidationErrorsDbContext.EntryDbChangeTracker.Entries在上面的方法中 会调用自动检测功能。 这个功能默认是开启的 当我们在做批量操作时 可以关闭这个来提高性能 .例如
using (var context = new UnicornsContext()) { try { context.Configuration.AutoDetectChangesEnabled = false; // Make many calls in a loop foreach (var unicorn in myUnicorns) { context.Unicorns.Add(unicorn); } } finally { context.Configuration.AutoDetectChangesEnabled = true; } }
http://my.oschina.net/wzzz/blog/113561
mvc EF 执行SQL语句
标签: