EntityFramework - CDUR
public class Context : DbContext { public DbSet<DEMO> DemoList{ get; set; } }
Context db = new Context();
增
db.DemoList.Add(DemoEntity);
db.SaveChange();
db.Entity(DemoEntity).State = EntityState.Added;
db.SaveChange();
State.Added 的方式不如 db.DemoList.Add() 快.
当有多个需要添加项的时候, 建议使用 AddRange();
删

var entity = new ApplicationDbContext.Three() { Id=2 }; using (var db = new ApplicationDbContext()) { db.Threes.Attach(entity); db.Threes.Remove(entity); db.SaveChanges(); }

var entity = new ApplicationDbContext.Three() { Id = 3 }; using (var db = new ApplicationDbContext()) { db.Entry(entity).State = EntityState.Deleted; db.SaveChanges(); }

db.DemoList.Remove(DemoEntity);
db.SaveChange();

db.Entry(DemoEntity).State = System.Data.Entity.EntityState.Deleted;
db.SaveChange();
EF 联级删除默认是 如果吧一个实体删除, 那么引用它的实体也会自动被删除
改
1. 直接从数据库检索出数据再修改

using (var db = new ApplicationDbContext()) { var old_entity = db.Twos.Single(t => t.Text = “90”); old_entity.Text = “update”; db.SaveChanges(); }
2. 直接更新不需要检索数据
通过修改实体状态来实现

var entity = new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { db.Entry(entity).State = EntityState.Modified; db.SaveChanges(); }
这个方式有个问题, 就是会吧没有主动更新到的字段都设置为 NULL
3. 指定字段更新

var entity = new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { // 设置实体状态为 Unchanged db.Entry(entity).State = EntityState.Unchanged; // 再设置要修改的字段为 IsModified db.Entry(entity).Property(“Text”).IsModified = true; db.SaveChanges(); }
4. 有时我们在更新的时候有些字段是不更新的, 但是这些字段又有可能会有些验证特性(比如不为空), 这样在保存时会出现验证不通过

public class MyFirst { public int MyFirstId { get; set; } public string Text { get; set; } [Required] public string Uu { get; set; } } /////////////////////////////////////////////////////////// var entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { db.Entry(entity).State = EntityState.Unchanged; db.Entry(entity).Property(“Text”).IsModified = true; db.SaveChanges(); }
这样可能会碰到 因为没有更新 Uu 字段, 令 Uu 字段为 Null 而无法通过验证
解决的办法是, 先让验证取消, 然后保存完之后再进行恢复验证

var entity = new ApplicationDbContext.MyFirst() { MyFirstId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { db.Entry(entity).State = EntityState.Unchanged; db.Entry(entity).Property(“Text”).IsModified = true; db.Configuration.ValidateOnSaveEnabled = false; db.SaveChanges(); db.Configuration.ValidateOnSaveEnabled = true; }
5. 在不同的上下文中更新

// 这样会出的问题是 // 在第二个上下文中会把数据全部更新 // (没有设置更新的则为 Null) // 原因是两个上下文, 状态没有传递 var entity; using(var db1 = new ApplicationDbContext()) { entity = db1.Twos.Single(m => m.Text = “90”); } entity.Text = “update”; using (var db = new ApplicationDbContext()) { DbEntityEntry entry = db.Entry(entity); entry.State = EntityState.Modified; db.SaveChanges(); }
第二种情况

var entity; using(var db1 = new ApplicationDbContext()) { entity = db1.Twos.Single(m => m.Text = “90”); } entity.Text = “update”; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); DbEntityEntry entry = db.Entry(entity); entry.State = EntityState.Modified; db.SaveChanges(); }
这种场景下, 与上面的却别就是第二个上下文也做了检索数据
这种情况下也会报错, 报错的原因是同一个上下文中出现两个主键相同的实体.
db 检索数据的时候跟踪了一个实体在上下文中, 又吧 db1 检索出来的实体加到 db 的上下文中, 一旦主键相同就报错了
解决方案是, 吧 entry.CurrentValues.SetValues(entity); 设置为上下文实体的值

var entity; using(var db1=new ApplicationDbContext()) { entity = db1.Twos.Single(m => m.Text = “90”); } entity.Text = “update”; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); DbEntityEntry entry = db.Entry(entity1); entry.CurrentValues.SetValues(entity); db.SaveChanges(); }
6. 同一个上下文中有实体存在的情况下用外部数据更新 ( 经常会用到 )

var entity = new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); DbEntityEntry entry = db.Entry(entity); entry.State = EntityState.Modified; db.SaveChanges(); }
会报错, 上下文中出现了同一个主键相同的实体
用指定更新试试

var entity= new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); DbEntityEntry entry = db.Entry(entity1); entry.CurrentValues.SetValues(entity); db.SaveChanges(); }
没有报错, 但是会更新全部数据, 不是指定的数据更新
尝试使用指定属性更新

var entity= new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); DbEntityEntry entry = db.Entry(entity1); entry.CurrentValues.SetValues(entity); entry.State = EntityState.Unchanged; entry.Property(“Text”).IsModified = true; db.SaveChanges(); }
结果是没有任何变化,
因为是 entry.State = EntityState.Unchanged; 吧 entry.CurrentValues.SetValues(entity) 改变的值还原回去了
解决方案是
使用 ObjectContext 的 ObjectStateEntry 设置当前值, 状态, 以及指定修改的属性

var entity= new ApplicationDbContext.Two() { TwoId = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { var entity1 = db.Twos.Single(m => m.Text = “90”); ObjectContext objectContext = ((IObjectContextAdapter)db).ObjectContext; ObjectStateEntry entry = objectContext.ObjectStateManager.GetObjectStateEntry(entity1); entry.ApplyCurrentValues(entity); entry.ChangeState(EntityState.Unchanged); entry.SetModifiedProperty(“Text”); db.SaveChanges(); }
封装一下

//对上上述更新方式做一个封装 //此封装可能会在并发时出错 public static class Test { //指定更新 public static void Update<TEntity>(this DbContext dbcontext, Expression<Func<TEntity, object>> propertyExpression, params TEntity entities) where TEntity : EntityBase { if (propertyExpression = null) { throw new ArgumentException(“propertyExpression”); } if (entities = null) { throw new ArgumentException(“entities”); } ReadOnlyCollection<MemberInfo> memberInfos = ((dynamic)propertyExpression.Body).Members; foreach (TEntity entity in entities) { try { DbEntityEntry<TEntity> entry = dbcontext.Entry(entity); entry.State = EntityState.Unchanged; foreach (var memberInfo in memberInfos) { entry.Property(memberInfo.Name).IsModified = true; } } catch { TEntity originalEntity = dbcontext.Set<TEntity>().Single(m => m.Id = entity.Id); ObjectContext objectContext = ((IObjectContextAdapter)dbcontext).ObjectContext; ObjectStateEntry objectEntry = objectContext.ObjectStateManager.GetObjectStateEntry(originalEntity); objectEntry.ApplyCurrentValues(entity); objectEntry.ChangeState(EntityState.Unchanged); foreach (var memberInfo in memberInfos) { objectEntry.SetModifiedProperty(memberInfo.Name); } } } } //提交保存 public static int SaveChanges(this DbContext dbContext, bool validateOnSaveEnabled) { bool isReturn = dbContext.Configuration.ValidateOnSaveEnabled != validateOnSaveEnabled; try { dbContext.Configuration.ValidateOnSaveEnabled = validateOnSaveEnabled; return dbContext.SaveChanges(); } finally { if (isReturn) { dbContext.Configuration.ValidateOnSaveEnabled = !validateOnSaveEnabled; } } } //全部更新 public static void Update1<TEntity>(this DbContext dbContext, params TEntity entities) where TEntity : EntityBase { if (dbContext = null) throw new ArgumentException(“dbContext”); if (entities = null) throw new ArgumentException(“entities”); foreach(TEntity entity in entities) { DbSet<TEntity> dbSet = dbContext.Set<TEntity>(); try { DbEntityEntry<TEntity> entry = dbContext.Entry(entity); if (entry.State = EntityState.Detached) { entry.State = EntityState.Modified; } } catch { TEntity oldEntity = dbSet.Find(entity.Id); dbContext.Entry(oldEntity).CurrentValues.SetValues(entity); } } } } public class EntityBase { public int Id { get; set; } } public class Three : EntityBase { public string Text { get; set; } public string Uu { get; set; } } //封装后的使用实例: var entity= new ApplicationDbContext.Three() { Id = 1, Text = “update” }; using (var db = new ApplicationDbContext()) { var entity1 = db.Threes.Single(m => m.Text = “90”); db.Update<ApplicationDbContext.Three>(m => new { m.Text }, entity); db.SaveChanges(); }
----------------------------------------------------------------------------------------------
// 直接保存
var EntityDemo = db.EntityDemoDBSet.Find(ID);
EntityDemo.SomeThing = Value;
db.SaveChange();
UpdateModel(EntityDemo);
db.SaveChange();
db.Entry(DemoEntity).State = System.Data.Entity.EntityState.Modified;
db.SaveChange();
可能会出现的问题
1. 当使用 与其他操作相同的数据库上下文的时候, 有可能会出现 重复键冲突错误.
错误原因:
假设先前已经使用过 Context_1 读取或者添加某数据, 那么在该 Context_1 便会存有该实体. 当要修改的时候, 往往要修改的对象并不是从 Context_1 中来, 而是从系统中 实例化出来, 这对于 Context_1 来说完全是一个新的实体, 则这时候进行修改操作实质上是进行了添加操作. 既然Context_1 中已经有该实体对应了主键了, 则肯定是会发生主键冲突错误.
解决方案:
1. 使用 新的 Context_1 ( 指新实例化出来的 )
2. 使用查询方法获取到 在 Context_1 的老数据, 并将其标注为 Detached 状态
3. 如果是泛型类的话, 则使用反射来获得 该对象的主键, 再利用该主键在 Context_1 追踪到这条老数据, 并标记为 Detached 状态
查
查询变量: 存储了查询的变量(并不存储实际的结果数据, 所以并没有实际访问数据库), 始终是一个可枚举(IEnumerable<T> 或 IQueryable<T>)的类型. 执行 foreach 的时候, 通过迭代变量访问数据库, 返回结果
结果变量: 实际存储了数据的变量, ( 查询结果 进行 .ToList(), .Max() 等需要读取数据的操作 会转变为结果变量)
// Lambda表达式
var query = db.EntityDemoList.Where(...);
// LINQ语句
var query = from i in db.EntityDemoList select i;
//多表查询 var query= from i in db.EntityDemoList join m in db.EntityDemoList2 on i.ID equals m.ID select i;
var query = 集合1.Join(
集合2,
a => a.Id,
b => b.集合1Id,
(a, b) => new SomeClass{ Id = a.Id });
// SQL语句直接查询
var sql = "select * from EntityDemoList"; var query = db.EntityDemoList.SqlQuery(sql);
1. 简单查询
int scores = { 90, 71, 82, 93, 75, 82 }; IEnumerable<int> scoreQuery = from score in scores where score > 80 orderby score descending select score; foreach (int testScore in scoreQuery) { //输出结果:93 90 82 82 Console.WriteLine(testScore); }
2. 分组查询
var queryLastNames = from student in students group student by student.LastName into newGroup orderby newGroup.Key select newGroup;
3. 内联查询
var query = from person in people join pet in pets on person equals pet.Owner select new { OwnerName = person.FirstName, PetName = pet.Name };
4. 分组连接
// 一个名字对应一个集合 var query = from person in people join pet in pets on person equals pet.Owner into gj select new { OwnerName = person.FirstName, Pets = gj };
5. 外联查询
var query = from person in people join pet in pets on person equals pet.Owner into gj from subpet in gj.DefaultIfEmpty() select new { person.FirstName, PetName = (subpet = null ? String.Empty : subpet.Name) };
6. 查询中处理 null
var query1 = from c in categories where c != null join p in products on c.ID equals (p = null ? null : p.CategoryID) select new { Category = c.Name, Name = p.Name }; var query = from o in db.Orders join e in db.Employees on o.EmployeeID equals (int?)e.EmployeeID select new { o.OrderID, e.FirstName };
7. 查询中处理异常
IEnumerable<int> dataSource; try { dataSource = GetData(); } catch (InvalidOperationException) { Console.WriteLine(“Invalid operation”); goto Exit; } var query = from i in dataSource select i * i; foreach (var i in query) Console.WriteLine(i.ToString()); Exit: Console.WriteLine(“Press any key to exit”); string files = { “fileA.txt”, “fileB.txt”, “fileC.txt” }; var exceptionDemoQuery = from file in files let n = SomeMethodThatMightThrow(file) select n; try { foreach (var item in exceptionDemoQuery) { Console.WriteLine(“Processing {0}”, item); } } catch (InvalidOperationException e) { Console.WriteLine(e.Message); }