一、修改数据

其实修改涉及的内容挺多的,是相对于其他操作来说比较繁琐。也是本文的重头戏。

虽然都是基础内容,但是也是值得细细品味的。

1、最简单直接的修改数据就是从数据库里检索出数据修改相应的字段即可

数据表:

Code:

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two old_entity = db.Twos.Single(t => t.Text == "90");

old_entity.Text = "update";

db.SaveChanges();

}

结果:

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

数据表:

Code:

通过修改实体的状态来实现

ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Modified;

db.SaveChanges();

}

结果:

这个方式有个不好地方,图中很明显的标注出来了,就是会一股脑更新全部字段,没有值就被更新成NULL。

3、指定字段更新

数据表:

Code:

修改实体状态为Unchanged.

设置指定属性的状态为修改

ApplicationDbContext.Two entity = new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Unchanged;

db.Entry(entity).Property("Text").IsModified = true;

db.SaveChanges();

}

结果:

4、禁用验证实体的有效性

有时我们在更新时有些字段是不更新的,但是这些字段又可能会有一些验证特性,比如不可以为空,这样我们在保存时会因实体验证不通过而报错。

实体:

Uu是必须的,不可为空

public class MyFirst

{

public int MyFirstId { get; set; }

public string Text { get; set; }

[Required]

public string Uu { get; set; }

}

Code:

ApplicationDbContext.MyFirst 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的特性的验证而报错了,我们只更新了Text,没有给Uu赋值,但是Uu又是不可以为空的

只要我们在保存前取消这种验证就可以了,在保存后恢复验证

修改后的Code:

ApplicationDbContext.MyFirst 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、在不同的上下文中更新数据

情况一

Code:

ApplicationDbContext.Two 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();

}

在这种场景下更新有一个问题是,数据会全部更新,并不是我们指定的Text更新,原因是不在一个上下文中,在另一个上下文中没有上一个上下文的状态,所以更新时没法判定就全部更新了。

数据图:

在db1获取数据时设置一个断点,手动修改数据库后的数据表:

结果数据:

会发现数据都被更新了,对比第二张图

情况二

Code:

ApplicationDbContext.Two entity;

using(var db1=new ApplicationDbContext())

{

entity = db1.Twos.Single(m => m.Text == "90");

}

entity.Text = "update";

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two 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);设置当前上下文实体的值。

Code:

ApplicationDbContext.Two entity;

using(var db1=new ApplicationDbContext())

{

entity = db1.Twos.Single(m => m.Text == "90");

}

entity.Text = "update";

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity1);

entry.CurrentValues.SetValues(entity);

db.SaveChanges();

}

数据图:

在db获取数据时设置一个断点,手动修改数据库后的数据表:

结果数据:

会发现只有指定的数据更新了,对比第二张图

6、同一个上下文中有实体存在的情况下用外部数据更新

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity);

entry.State = EntityState.Modified;

db.SaveChanges();

}

会报错,原因和上面情况一样,上下文中出现了主键一样的多个实体,本来有一个实体了,又加载了一个主键一样的实体,就报错了。

用上述方法解决试试看

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two entity1 = db.Twos.Single(m => m.Text == "90");

DbEntityEntry entry = db.Entry(entity1);

entry.CurrentValues.SetValues(entity);

db.SaveChanges();

}

没有报错,成功更新数据,但是问题是全部数据都被更新,不是我们指定的数据更新

结果数据:

尝试使用指定属性更新:

结果你会发现数据没有发生任何变化,原因是entry.State = EntityState.Unchanged;把ntry.CurrentValues.SetValues(entity);改变得值有还原回去了。

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two 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();

}

解决上述问题:

如果要解决上述问题应该使用ObjectContext的ObjectStateEntry设置当前值,状态,以及指定修改的属性

Code:

ApplicationDbContext.Two entity= new ApplicationDbContext.Two() { TwoId = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Two 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; }

}

封装后的使用实例:

pplicationDbContext.Three entity= new ApplicationDbContext.Three() { Id = 1, Text = "update" };

using (var db = new ApplicationDbContext())

{

ApplicationDbContext.Three entity1 = db.Threes.Single(m => m.Text == "90");

db.Update<ApplicationDbContext.Three>(m => new { m.Text }, entity);

db.SaveChanges();

}

至此更新部分已经全部完毕

Ps:其实扩展方法update有个坑,就是一但出现并发时就会报错走catch,而其实不是想要的结果,这是个忽略的地方,并发应该抛出错误,用catch是忽略了并发的情况...额...

二、添加数据

简单明了没有啥好说的

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Text = "我哦哦哦" };

using (var db = new ApplicationDbContext())

{

db.Threes.Add(entity);

db.SaveChanges();

}

数据图:

三、删除数据

简单明了没啥好说的

通过Attach把实体加载到上下文,关键点就是实体要存在于上下文中

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id=2 };

using (var db = new ApplicationDbContext())

{

db.Threes.Attach(entity);

db.Threes.Remove(entity);

db.SaveChanges();

}

Code:

ApplicationDbContext.Three entity = new ApplicationDbContext.Three() { Id = 3 };

using (var db = new ApplicationDbContext())

{

db.Entry(entity).State = EntityState.Deleted;

db.SaveChanges();

}

四、查询

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)

{

Console.WriteLine(testScore);

}

//输出结果:93 90 82 82

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);

}

更多关于查询请查考MSDN,里面很详细

https://msdn.microsoft.com/zh-cn/library/bb384065.aspx

一篇文章告诉你如何使用EF CodeFirst做增删改查的更多相关文章

  1. Entity - 使用EF框架进行增删改查 - 模型先行

    模型先行:先创建数据库实体模型,然后再进行数据库的增删改查. 基本步骤是不变的,可参照 <Entity - 使用EF框架进行增删改查 - 数据库先行> 其中的不同是,在创建数据库实体模型的 ...

  2. MVC学习-用EF做增删改查

    在做增删改查先,先介绍几个知识点: 1.代理类 在将对象方法EF数据上下文时,EF会为该对象封装 一个代理类对象, 同时为该对象的每一个属性添加一个标志:unchanged, 当对该对象某个属性进行操 ...

  3. 用DBContext (EF) 实现通用增删改查的REST方法

    我们用ADO.NET Entity Data Model来生成实体类后,一般都会对这些类进行基本的增删改查操作,如果每个类都要写这些基本的方法,实在太乏味了.下面就是通过step by step的方式 ...

  4. C# 数据操作系列 - 8. EF Core的增删改查

    0.前言 到目前为止,我们看了一下如何声明EF Core的初步使用,也整体的看了下EF Core的映射关系配置以及导航属性的配置. 这一篇,我带大家分享一下,我在工作中需要的EF Core的用法. 1 ...

  5. Entity - 使用EF框架进行增删改查 - 数据库先行

    数据库先行:先创建数据库,然后进行增删查该操作. 要操作的表结构(表名:Tb_Category): 创建一个控制台程序: 添加一个ADO.NET实体数据模型: 1.对控制台程序右键 2.选择ADO.N ...

  6. .Net EF框架的增删改查

    创建上下文对象: WordBoradEntities db = new WordBoradEntities(); 添加: //1.1创建实体对象 User uObj = new User() { uN ...

  7. VS2012里面使用EF框架的增删改查和分页的方法

    public class BaseRepository<T> where T : class    {        //实例化EF框架        DataModelContainer ...

  8. .net EF框架-实现增删改查

    声明一个EF上下文对象 Model dbContext = new Model(); 添加操作(向表中插入一条数据) //声明一个表的实体 Contact contact = new Contact( ...

  9. 二、MVC3+EF单表增删改查

    document 表为例 写入静态类 NorthwindDataProvider: Controller可直接调用:如 //获取document表全部数据 NorthwindDataProvider. ...

随机推荐

  1. Codeforces Beta Round #91 (Div. 1 Only) E. Lucky Array

    E. Lucky Array Petya loves lucky numbers. Everybody knows that lucky numbers are positive integers w ...

  2. HDU——1134 Game of Connections

    Game of Connections Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  3. MVC WebApi 将返回值改为JSON格式

    新增一个类: public class BrowserJsonFormatter : JsonMediaTypeFormatter { public BrowserJsonFormatter() { ...

  4. QT如何修改编程语言的字体

    工具-选项,然后在文本编辑器中设置要的字体

  5. 小胖说事22-----iOS开发技巧之取消键盘响应和截屏功能

    1.UILable内容模糊 在非Retina的iPad mini 的屏幕上,一个UILable的frame的origin值假设是有小数位(如0.5),就会造成显示模糊,所以不妨用整数值的origin. ...

  6. Tcl学习之--命名空间

    Tcl解释器将全部的命令和全局变量分组管理.这些小组称为命名空间,一个命名空间中的命令和变量不会影响到还有一个命名空间.这些命名空间呈树形组织.一个命名空间的命令能够被还有一个命名空间引入.命名空间树 ...

  7. Linux下CMake使用介绍

    CMake是一个跨平台的编译自己主动配置工具,它使用一个名为CMakeLists.txt的文件来描写叙述构建过程,能够产生标准的构建文件.它能够用简单的语句来描写叙述全部平台的安装(编译过程).它能够 ...

  8. 递归,迭代,堆栈三种方式实现单链表反转(C++)

    #author by changingivan# 2016.04.12#include <iostream> #include <stack> using namespace ...

  9. ADT 压缩包 R23.0.0

    http://pan.baidu.com/s/1qWLjs2w

  10. Linux如何使用cURL分割下载大文件

    Linux如何使用cURL分割下载大文件 - 51CTO.COM http://os.51cto.com/art/201508/489368.htm