EF6基本使用
1.EF基本搭建
EF也用了好几年了,但是在日常开发的时候,有时候因为偷懒,有时候因为赶项目,很多代码,多半就是Ctrl+C和Ctrl+V,慢慢的一些代码怎么写都忘记了,虽然觉得很简单,但是就是记不起来怎么写,逐渐退化,所以记录一下,后续再赋值粘贴也好找一些,免得打开项目。
在此以.Net FramWork 控制台搭建简单的Demo使用的模式是DBFirst,个人觉得现在多半还是数据库设计和代码还是分开的。
1.创建数据库和表,这里使用关联表,一个主表一个从表,抽象出简单的业务关系为一个员工持有哪些设备,而关系是一对多。
--创建数据库
CREATE DATABASE EfDemo;
GO
USE EfDemo;
GO
--创建员工表
CREATE TABLE [dbo].[Employee]
([id] [INT] IDENTITY(1, 1) NOT NULL,
[Code] [NVARCHAR](20) NULL,
[Name] [NVARCHAR](20) NULL,
);
--创建设备表
CREATE TABLE [dbo].[Device]
([DeviceId] [INT] IDENTITY(1, 1) NOT NULL,
[id] [INT] NULL,
[DeviceName] [NVARCHAR](20) NULL
);
1.首先NuGet 安装EntityFramework,至于什么版本看一下介绍,选择对应框架的版本,我的是4.8安装的EF版本是6.2

2.在配置文件中设置连接字符串
<connectionStrings>
<add name="efConstr" connectionString="Data Source=192.168.0.106;Initial Catalog=EfDemo;User ID=sa;Password=sa@123456" providerName="System.Data.SqlClient" />
</connectionStrings>
3.创建员工实体类和设备实体类,并添加相关属性,添加2个方法添加和删除Device信息
[Table("Employee")] 表映射
[Key] 主键
[Required] 必填
[Column("Name")] 列名映射
[StringLength(1000)] 设置长度,如果是dbfirst记得与数据库长度匹配
[Table("Employee")]
public class EmployeeEntity
{
public EmployeeEntity()
{
DeviceEntities = new HashSet<DeviceEntity>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Column(Order = 1)]
[Required]
public int id { get; set; }
//将数据库字段Name映射别名为"mingzi "
[Column("Name")]
public string mingzi { get; set; }
public string Code { get; set; }
public virtual ICollection<DeviceEntity> DeviceEntities { get; set; }
public void AddDevice(DeviceEntity entity)
{
this.DeviceEntities.Add(entity);
}
public void RemoveDevice(DeviceEntity entity)
{
this.DeviceEntities.Remove(entity);
}
}
[Table("Device")]
public class DeviceEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int DeviceId { get; set; }
public int id { get; set; }
public string DeviceName { get; set; }
}
4.创建UserContext上下文,继承自DbContext
public class UserContext: DbContext
{
public UserContext()
: base("name=efConstr")
{
}
public virtual DbSet<EmployeeEntity> EmployeeEntities { get; set; }
}
2.EF查询
查询员工和设备数据,为了查询方便已经在实体模型上设置了,所以不需要连表查询,直接根据员工查出关联表的数据,我们想在程序中输出ef执行的sql日志可以使用
userContext.Database.Log = sql => { Console.WriteLine(sql); };
1.使用Find即时 查询id为1的数据,此时执行代码是直接实时查询数据库。
using (UserContext userContext = new UserContext())
{
var result = userContext.EmployeeEntities.Find(1);
}
2.使用Where延时查询 查询id大于0的数据,在执行循环之前此时还未提交到数据库,得到的是一个IQueryable可以使用ToList()或者对IQueryable进行循环就会直接提交到数据库
但是不建议直接使用ToList
public static List<EmployeeDto> SerachEmployeeInfo()
{
List<EmployeeDto> employees = new List<EmployeeDto>();
using (UserContext userContext = new UserContext())
{
//是一个IQueryable,此时并不会提交到数据库
var result = userContext.EmployeeEntities.Where(x => x.id > 0);
//虽然有多个但是只是拼接表达式,ToList时提交
result = result.Where(x => x.id == 2).ToList();
foreach (var item in result)
{
EmployeeDto employeeDto = new EmployeeDto();
employeeDto.Id = item.id;
employeeDto.Name = item.mingzi;
employeeDto.Code = item.Code;
employeeDto.DeviceEntities = item.DeviceEntities.ToList();
employees.Add(employeeDto);
}
}
return employees;
}
3.使用连接查询,默认为内连,如果需要左连接就需要将2个合并插入一个新的表,然后使用DefaultIfEmpty() 定义可为空
public static List<EmployeeDto> SerachEmployeeInfoByJoin()
{
List<EmployeeDto> employees = new List<EmployeeDto>();
using (UserContext userContext = new UserContext())
{
List<int> ins = new List<int> { 2 };
//使用内连接查询
var result = from u in userContext.EmployeeEntities
join c in userContext.DeviceEntities on u.id equals c.id
select new
{
Id = u.id,
Name = u.mingzi,
DeviceName = c.DeviceName
};
//使用左连接查询
var result = from u in userContext.EmployeeEntities
join c in userContext.DeviceEntities on u.id equals c.id
into leftTable
from lt in leftTable.DefaultIfEmpty()
select new
{
Id = u.id,
Name = u.mingzi,
DeviceName = c.DeviceName
};
//提交到数据库,并且遍历投影出的新的数据
foreach (var item in result)
{}
}
return employees;
}
4.使用EF执行sql语句,适合比较复杂的sql语句,主要依靠ExecuteSqlCommand和SqlQuery,调用存储过程也是同样的道理
public static int SerachEmployeeInfoBySql ()
{
using (UserContext userContext = new UserContext())
{
DbContextTransaction trans = null;
try
{
trans = userContext.Database.BeginTransaction();
string sqlExecute = "Update Employee set Name ='EF测试' WHERE Id=@Id";
//查询语句
//string sqlQuery = "Select*from Employee WHERE Id=@Id"
SqlParameter parameter = new SqlParameter("@Id", 1);
//执行ExecuteSqlCommand增删改
int executeResult = userContext.Database.ExecuteSqlCommand(sqlExecute, parameter);
//var result = userContext.Database.SqlQuery<EmployeeEntity>(sqlQuery, parameter).ToList<EmployeeEntity>();
trans.Commit();
return executeResult;
}
catch (Exception ex)
{
if (trans != null)
trans.Rollback();
throw ex;
}
finally
{
trans.Dispose();
}
}
}
3.EF增删改使用
1.新增一笔数据,这里使用的是异步方法,其实同步方法一样的道理,由于Employee和Device是主从关系,所以执行下面的代码同时会向Device表也插入一条
- 1.如果在一个上下文中再次将mingzi 改为"同一上下文中再次赋值",那么就会修改前面插入的数据,因为在一个上下文中会进行
数据跟踪
static async Task AddEmployee()
{
using (UserContext userContext = new UserContext())
{
EmployeeEntity entity = new EmployeeEntity();
entity.mingzi = "新增数据1";
entity.Code = "A123";
//导航属性插入值
entity.AddDevice(new DeviceEntity { DeviceName = "ipad" });
userContext.EmployeeEntities.Add(entity);
//执行SaveChangesAsync()数据才会提交
await userContext.SaveChangesAsync();
//同上下文中再次赋值,就会修改mingzi的值
entity.mingzi = "同一上下文中再次赋值";
await userContext.SaveChangesAsync();
}
return result;
}
2.使用EF修改数据,如果直接修改是无效的
- 2.1.在同一上下文中修改,通常在工作中的做法是需要先把对象查询出来,然后修改对应的值。
同一上下文修改
static async Task UpdateEmployee()
{
using (UserContext userContext = new UserContext())
{
//先查询在修改
var content = await userContext.EmployeeEntities.FindAsync(7);
content.mingzi = "被修改的值";
await userContext.SaveChangesAsync();
}
}
- 2.2.在不同上下文中修改值,我们使用
Attach的目的就是把一个没有被dbContext 跟踪的对象附加到新的上下文中,使其被跟踪,必须先附加再赋值才能生效,如果先赋值那就需要在上下文中将对象的状态设置为EntityState.Modified
不同上下文修改
static async Task AddEmployee()
{
EmployeeEntity entity = null;
using (UserContext userContext = new UserContext())
{
entity = new EmployeeEntity();
entity.mingzi = "新增数据1";
entity.Code = "A123";
entity.AddDevice(new DeviceEntity { DeviceName = "ipad1" });
userContext.EmployeeEntities.Add(entity);
await userContext.SaveChangesAsync();
}
using (UserContext userContext = new UserContext())
{
//先附加再修改
userContext.EmployeeEntities.Attach(entity);
entity.mingzi = "不同上下文先附加再修改值";
await userContext.SaveChangesAsync();
//先修改再设置状态为Modified
entity.mingzi = "不同上下文先修改值再设置状态";
userContext.Entry<EmployeeEntity>(entity).State = EntityState.Modified;
await userContext.SaveChangesAsync();
}
}
- 2.3.按照上面的方式,EF在执行时生成的sql会将所有的字段都更新一遍,我们可以设置只对某个
属性字段更新,在执行sql时只会更新那一个字段,前提需要对对象进行Attach,然后再设置字段状态。
using (UserContext userContext = new UserContext())
{
entity.mingzi = "不同上下文修改值";
userContext.EmployeeEntities.Attach(entity);
//通知context mingzi属性被修改
userContext.Entry<EmployeeEntity>(entity).Property<string>("mingzi").IsModified = true;
await userContext.SaveChangesAsync();
}
3.删除数据的方式和修改类似,通用的是查询出来然后是使用Remove,如果不同上下文,我们需要Attach或者将状态更改为EntityState.Deleted
static async Task removeEmployee(int id)
{
using (UserContext userContext = new UserContext())
{
var emp = userContext.EmployeeEntities.Where(x => x.id == id).FirstOrDefault();
userContext.EmployeeEntities.Remove(emp);
await userContext.SaveChangesAsync();
}
}
- 3.1.不同上下文删除使用
附加或者设置状态
static async Task removeEmployee(int id)
{
EmployeeEntity entity = null;
using (UserContext userContext = new UserContext())
{
entity = userContext.EmployeeEntities.Where(x => x.id == id).FirstOrDefault();
}
using (UserContext userContext = new UserContext())
{
//设置实体状态为删除
// userContext.Entry(entity).State = EntityState.Deleted;
//附加到当前上下文
userContext.EmployeeEntities.Attach(entity);
//执行删除
userContext.EmployeeEntities.Remove(entity);
await userContext.SaveChangesAsync();
}
}
4.Context上下文
1.下面在一个上下文里面执行多个操作,一次SaveChanges()是保存全部的变化,假如中间有一个失败,那所有的都将失败,可以理解到SaveChanges是事务的结束,所以不能全局使用
static void UpdateEmployee()
{
using (UserContext userContext = new UserContext())
{
try
{
var content = userContext.EmployeeEntities.Find(22);
content.mingzi = "一个上下文修改第一个值";
var content1 = userContext.EmployeeEntities.Find(23);
content1.mingzi = "一个上下文修改第二个值撒啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊撒啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊";
userContext.SaveChanges();
}
catch (Exception ex) { throw ex; }
}
}
2.不同的Context不能连接查询,除非load到内存之后再去操作,如果是多线程或者多个请求,最好多个Context

5.查询本地缓存
1.在EF中查询是有缓存的,例如下面在使用Where时每一次都会去数据库查询,但是使用Find时,他会现在本地内存中查找一次,如果前面查询有结果,那就直接使用,那么就有可能产生脏读,但是对性能提升有帮助,使用时根据自身需求而定。
using (UserContext userContext = new UserContext())
{
var result = userContext.EmployeeEntities.Where(x => x.id < 3).ToList();
var result1 = userContext.EmployeeEntities.Where(x => x.id ==2).ToList();
var result2 = userContext.EmployeeEntities.Find(1);
var result3 = userContext.EmployeeEntities.Where(x => x.id == 1).ToList();
}
2.如果不希望查询出的结果在内存中缓存,可以使用AsNoTracking不在内存中拷贝副本,直接返回,就算后续使用Find也不会读取内存
using (UserContext userContext = new UserContext())
{
var result = userContext.EmployeeEntities.Where(x => x.id < 3).AsNoTracking().ToList();
}
``
###### 6.导航属性以及延迟加载
1.主从查询丢弃子表查询,在上下文中使用`LazyLoadingEnabled =fasle`
```cs
userContext.Configuration.LazyLoadingEnabled = false;
2.使用Include,不延迟加载将数据一次性加载出来
using (UserContext userContext = new UserContext())
{
var result = userContext.EmployeeEntities.Include("DeviceEntities").Where(x=>x.id>0);
foreach (var item in result)
{
EmployeeDto employeeDto = new EmployeeDto();
employeeDto.Id = item.id;
employeeDto.Name = item.mingzi;
employeeDto.Code = item.Code;
employeeDto.DeviceEntities = item.DeviceEntities.ToList();
employees.Add(employeeDto);
}
}
3.主从表的级联删除,前提是需要修改数据库外键的删除规则为级联
using (UserContext userContext = new UserContext())
{
entity = userContext.EmployeeEntities.Where(x => x.id == id).FirstOrDefault();
userContext.EmployeeEntities.Remove(entity);
userContext.SaveChanges();
}
EF6基本使用的更多相关文章
- MVC5+EF6+MYSQl,使用codeFirst的数据迁移
之前本人在用MVC4+EF5+MYSQL搭建自己的博客.地址:www.seesharply.com;遇到一个问题,就是采用ef的codefirst模式来编写程序,我们一般会在程序开发初期直接在glob ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)
开发工具:VS2015(2012以上)+SQL2008R2以上数据库 您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB 升级后界面效果如下: 任务调度系统界面 http: ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入
系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...
- 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- VS2012+EF6+Mysql配置心路历程
为了学习ORM,选择了EntityFramework,经历了三天两夜的煎熬,N多次错误,在群里高手的帮助下,终于成功,现在将我的心路历程记录下来,一是让自己有个记录,另外就是让其它人少走些弯路. 我的 ...
- Linux学习日记-使用EF6 Code First(四)
一.在linux上使用EF 开发环境 VS2013+mono 3.10.0 +EF 6.1.0 先检测一下EF是不是6的 如果不是 请参阅 Linux学习日记-EF6的安装升级(三) 由于我的数据库 ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级
系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构
系列目录 前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多.主要集中增删该查每个模块都有,所以本次是为封装相同接口方法 如果你想了解怎么重构普通的接口DAL层请查 ...
- Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理
这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...
随机推荐
- 操作系统综合题之“用记录型信号量机制的wait操作和signal操作写出三个进程的同步代码(水果进箱问题-代码补充)”
1.问题:假设一个水果赛选系统由三个进程A.B.C组成.进程A每次取一个水果,之后存放在货架F上,F的容量为每次只能存放一个水果.若货架上存放的是苹果则让进程B取出,并存放到苹果箱中:若货架上存放的是 ...
- vue3 基础-CompositionAPI - setup
之前介绍的是一些关于代码复用的问题, 如 mixin, plugin 等. 从本篇开始呢, 就将来学习一波 vue3 的新特性, 即 Composition API 咱之前的写法, 即把各种逻辑, 方 ...
- C#中无法将文件”obj\debug\XXX.dll复制到“bin\Debug\XXX.dll” 拒绝访问
较为方便有效的方法就是,把项目属性中的"应用程序集"的"程序集名称"修改为另一个名称即可.
- django-channels自定义中间件验证token的方法
测试版本: python 3.8 djnago 3.2 channels 3.0 需求 在使用channels 建立websocket连接的时候,需要验证客户端的token,并保存一些关键信息 实现原 ...
- 基于FPGA的超声波雷达感应预警系统 全过程记录
FPGA系统开发 综合实验记录 实验时间节点与想法记录 2023.4.24 新建本文档.目前决定有以下两个方案,要根据学校发的器件和自己的水平和后面时间决定. 课设想法 具体情况 基于FPGA的高速运 ...
- 慢查询导致任务执行hang住
上线上了大半天,原因:因为慢查询了导致跑不出来,后来同事帮忙看了下发现慢查询了,程序hang住了 select * from table where cdate = '2023-02-01' and ...
- 改造jsp项目的alert框和confirm框
背景 之前项目的模态框改造完成,业务也想把页面中的提示框和确认框也改造一下:这里记录一下改造中的细节. 之前项目中的提示框和确认框用的是浏览器自带的 alert 和 confirm.改造之前无法支持业 ...
- linux搭建natapp内网穿透服务器
参考教程:window版本 https://www.jianshu.com/p/8897106c8d3dlinux版本 https://natapp.cn/article/natapp_newbie相 ...
- Rust修仙之道 第二章:气流变换 · 驭控条件与循环之术
第二章:气流变换 · 驭控条件与循环之术 在掌握变量与法印函数之后,顾行云进入了修炼的下一个瓶颈--如何让灵气术式随境而变.适时而动? 他夜读<Rust·变通篇>,心有所感:"灵 ...
- C# 通过反射 XML 互转 Model 类
实操 <Info xmlns=""> <Error>User 錯誤</Error> </Info> public class Res ...