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();
}
View Code
var entity = new ApplicationDbContext.Three() { Id = 3 };     
using (var db = new ApplicationDbContext()) 
{
    db.Entry(entity).State = EntityState.Deleted;
    db.SaveChanges(); 
}
View Code
db.DemoList.Remove(DemoEntity);
db.SaveChange();
View Code
db.Entry(DemoEntity).State = System.Data.Entity.EntityState.Deleted;
db.SaveChange();
View Code

 

EF 联级删除默认是 如果吧一个实体删除, 那么引用它的实体也会自动被删除

 


 

1. 直接从数据库检索出数据再修改

using (var db = new ApplicationDbContext())
{
   var old_entity = db.Twos.Single(t => t.Text = “90”);
  old_entity.Text = “update”;
  db.SaveChanges();
}
View Code

 

2. 直接更新不需要检索数据 

通过修改实体状态来实现

var entity = new ApplicationDbContext.Two() { TwoId = 1, Text = “update” };
using (var db = new ApplicationDbContext())
{
  db.Entry(entity).State = EntityState.Modified;
  db.SaveChanges();
}
View Code

这个方式有个问题, 就是会吧没有主动更新到的字段都设置为 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();
}
View Code

 

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();
}
View Code

这样可能会碰到 因为没有更新 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;
}
View Code

 

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();
}
View Code

 

第二种情况

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();
}
View Code

 

这种场景下, 与上面的却别就是第二个上下文也做了检索数据

这种情况下也会报错, 报错的原因是同一个上下文中出现两个主键相同的实体.

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();
}
View Code

 

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();
}
View Code

会报错, 上下文中出现了同一个主键相同的实体

用指定更新试试

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();
}
View Code

没有报错, 但是会更新全部数据, 不是指定的数据更新

尝试使用指定属性更新

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();
}
View Code

结果是没有任何变化,

因为是 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();
}
View Code

封装一下

//对上上述更新方式做一个封装
//此封装可能会在并发时出错
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(); 
}
View Code

 

 ----------------------------------------------------------------------------------------------

// 直接保存
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 = { 907182937582 };
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); 
    }

 

posted @ 2015-04-21 12:37  `Laimic  阅读(247)  评论(0)    收藏  举报