1, 实体状态
我们通过 EF 来对数据库进行操作并持久化到数据库, 那么 EF 必然通过 EF 上下文来维护实体的状态, 明确知道每一个状态所对应的操作. 也就是说 EF 通过上下文负责跟踪实体的状态. EF 实体状态存在命名空间 System.Data.Entity 下的 EntityState 枚举中
1.1,Added
Added 状态针对添加操作, 当标记为此状态时, 表名实体被上下文追踪但是不存在数据库中, 当调用 SaveChange() 的时候会插入到数据库中. 标记 Added 状态有两种: 一种是间接标记, 通过 Add 方法调用; 另一种显示标记通过 Entry 方法调用代码如下
- var cus = new Customer() {
- Name="魏杨杨",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Customer.Add(cus);
- db.SaveChanges();
- // 或者是
- var cus = new Customer() {
- Name="魏杨杨",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Entry(cus).State = System.Data.Entity.EntityState.Added;
- db.SaveChanges();
- 1.2,UnChangeed
实体类被 EF 上下文所追踪, 但是存在数据库中的值未发生改变. 若一个实体类不存在与数据库, 但是该实体要被上下文所追踪, 同时该实体值未发生改变就可以通过 Attach 进行附加追踪, 然后标记为 UnChanged 状态
- using (var db =new WYDBContext())
- {
- var cus = new Customer() {
- Name="魏杨杨",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Customer.Attach(cus);
- db.Entry(cus).State = System.Data.Entity.EntityState.Unchanged;
- db.SaveChanges();
- }
- 1.3,Modified
实体被 EF 上下文所追踪并存在于数据库中, 同时部分或者所有属性值已经被更改, 当调用 SaveChange() 时则更新到数据库中. 注意: 在 EF6.0 以上的版本中不存在 Update 方法. 看数据库里面的值
- using (var db =new WYDBContext())
- {
- var cus = new Customer() {
- Zj=1,
- Name="魏杨杨 22",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Entry(cus).State = System.Data.Entity.EntityState.Modified;
- db.SaveChanges();
- }
一般我做更改的时候都不会这么麻烦, 当修改的时候只要传来这一列的参数 ID 查找出当前列就直接修改了, 我这种方法用的多一点: 比如
- public ActionResult Edit(int id)
- {
- using (var db = new WYDBContext())
- {
- var model = db.Customer.Find(id);
- model.Name = "Wyy333";
- model.Age = 19;
- db.SaveChanges();
- return View(model);
- }
- }
- 1.4,Deleted
实体类被 EF 上下文所追踪并存在于数据库中, 当标记为 Deleted 状态时, 调用 SaveChange() 方法时数据将在数据库中删除, 和 Added 状态一样可以调用 Remove 或者 RemoveChange 方法标记实体为 Deleted 状态, 或者通过 Entry 方法标记
- using (var db =new WYDBContext())
- {
- var cus = new Customer() {
- Zj=1,
- Name="魏杨杨 22",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Entry(cus).State = System.Data.Entity.EntityState.Deleted;
- db.SaveChanges();
- }
- // 或者
- using (var db =new WYDBContext())
- {
- var cus = new Customer() {
- Zj=1,
- Name="魏杨杨 22",
- Age=18,
- Email="30119459@qq.com",
- AddTime=DateTime.Now
- };
- db.Customer.Remove(cus);
- db.SaveChanges();
- }
- // 或者这种删除是最常见了的吧我见过的都是这样的
- using (var db = new WYDBContext())
- {
- var model = db.Customer.Find(id);
- db.Customer.Remove(model);
- db.SaveChanges();
- return View(model);
- }
2, 加载关联数据
在 EF6.0 以上的版本中, 数据加载方式有 3 种: 延迟加载, 饥渴加载, 显示加载. 三种加载方式都有其场景, 利用不同将导致性能问题.
2.1,Lazy Loading(延迟加载)
顾名思义就是当我门需要的时候才加载也就是说的按需加载. 当第一次访问指向实体或者实体的属性时, 实体或者实体的集合将从数据库加载, 访问导航属性是相关的对象或者子对象不会自动加载. virtual 的导航属性就是延迟加载. 摸人家情况下 EF 启动延时加载. 我们也可以在 EF 上下文派生类中手动关闭延迟加载
在订单里面加点数据
当查询 Customer 的时候看到 Order 还没有计算,
下面来获取 Order 数据
现在我们关闭延时加载效果 再看看
- public WYDBContext():base("SqlConn")
- {
- Configuration.LazyLoadingEnabled = false;
- }
这不就报错了吗. 现在我们就看到延迟加载的本质: 只有当调用者使用的时候才会计算结果.
2.2,Eager Loading(饥饿加载)
查询实体的时候可以加载相关实体或者子实体作为查询的一部分, 加载父对象同时加载子对象, 在 EF 中可以使用 DbSet<T>.Include() 方法来实现饥渴加载. 和延迟加载不同的是我们用与不用子对象都会被加载进来.
- using (var db =new WYDBContext())
- {
- var cs = db.Customer.Include("Order").ToList();
- var cs2 = db.Customer.Include(p=>p.Order).ToList();//using System.Data.Entity;
- }
现在可以看出饥饿加载的本质: 提前加载所有数据
2.3 Explicitly Loading(显示加载)
延迟执行有延迟加载个显示加载两种方式, 即使我们禁用了延迟加载, 然然可以通过显示加载来延迟加载相关实体, 通过 DbEntityEntry<T>.Reference("").Load() 加载实体. 通过 DbEntityEntry<T>.Collection("").Load() 加载集合
- using (var db =new WYDBContext())
- {
- var cs = db.Customer.ToList().FirstOrDefault();
- var order = db.Entry(cs).Collection(x => x.Order).Query().ToList();
- var or = db.Order.ToList().FirstOrDefault();
- db.Entry(or).Reference(x => x.Customer).Load() ;
- }
效果如期而至就不贴了. 可以总结出显示加载的本质: 即使禁用延迟加载任然可以延迟执行
3, 在 Ef 中执行 Sql
3.1, 在实体上执行原始查询
在 EF 中可以通过 SqlQuery 来查询数据 有如下两种方法
efDbContext.Database.SqlQuery < 实体类名 >(string sql , params object[] parameters)
efDbContext. 实体类. SqlQuery(string sql , params object[] parameters)
Tolist() 后将所有数据加载到内存中;
- using (var db =new WYDBContext())
- {
- // 结果会保存到数据库中
- var c2 = db.Customer.SqlQuery("Select * from Customer").ToList();
- c2.Last().Email = "wyy22@qq.com";
- db.SaveChanges();
- // 结果不会保存到数据库中
- var c1= db.Database.SqlQuery<Customer>("Select * from Customer").ToList();
- c1.Last().Email = "wyy@qq.com";
- db.SaveChanges();
- }
这里要把列名弄了跟数据库里面的对应就是不要去别名了 我出错是因为这里一个是 Name 一个是 NameWyy 哈哈 挖坑给自己跳
- [Column("NameWYY", TypeName = "nvarchar")]// 我加了 WYY 看效果
- [StringLength(50, ErrorMessage = "{0} 长度不能超过 50 个字符")]
- [Display(Name = "姓名")]
- public string Name { get; set; }
注意:
efDbContext.Database.SqlQuery < 实体类名 >(string sql , params object[] parameters) 此方法查询在数据库 database 上, 实体不会被上下文跟踪
efDbContext. 实体类. SqlQuery(string sql , params object[] parameters) 查询在上下文的实体集合 DbSet 上, 实体会被上下文跟踪
3.2, 在 EF 中执行 Sql: 删除, 修改
- using (var db =new WYDBContext())
- {
- // 第一种
- string ema = "wwww@qq.com";
- string sql = $"Update Customer set email='{ema}'where Zj=1;";
- db.Database.ExecuteSqlCommand(sql);
- // 第二种 可以防止 Sql 注入
- SqlParameter[] para = { new SqlParameter("@Emale", "wwww@qq222.com"),new SqlParameter("@Zj",1) };
- var sql1 = "Update Customer set email=@Emale where Zj=@Zj;";
- db.Database.ExecuteSqlCommand(sql1,para);
- }
删除也是一样的
来源: https://www.cnblogs.com/w5942066/p/12162595.html