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语句,主要依靠ExecuteSqlCommandSqlQuery,调用存储过程也是同样的道理

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.新增一笔数据,这里使用的是异步方法,其实同步方法一样的道理,由于EmployeeDevice是主从关系,所以执行下面的代码同时会向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基本使用的更多相关文章

  1. MVC5+EF6+MYSQl,使用codeFirst的数据迁移

    之前本人在用MVC4+EF5+MYSQL搭建自己的博客.地址:www.seesharply.com;遇到一个问题,就是采用ef的codefirst模式来编写程序,我们一般会在程序开发初期直接在glob ...

  2. ASP.NET MVC5+EF6+EasyUI 后台管理系统(1)-前言与目录(持续更新中...)

    开发工具:VS2015(2012以上)+SQL2008R2以上数据库  您可以有偿获取一份最新源码联系QQ:729994997 价格 666RMB  升级后界面效果如下: 任务调度系统界面 http: ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(63)-Excel导入和导出-自定义表模导入

    系列目录 前言 上一节使用了LinqToExcel和CloseXML对Excel表进行导入和导出的简单操作,大家可以跳转到上一节查看: ASP.NET MVC5+EF6+EasyUI 后台管理系统(6 ...

  4. 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  5. 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  6. VS2012+EF6+Mysql配置心路历程

    为了学习ORM,选择了EntityFramework,经历了三天两夜的煎熬,N多次错误,在群里高手的帮助下,终于成功,现在将我的心路历程记录下来,一是让自己有个记录,另外就是让其它人少走些弯路. 我的 ...

  7. Linux学习日记-使用EF6 Code First(四)

    一.在linux上使用EF 开发环境 VS2013+mono 3.10.0 +EF 6.1.0 先检测一下EF是不是6的 如果不是  请参阅 Linux学习日记-EF6的安装升级(三) 由于我的数据库 ...

  8. ASP.NET MVC5+EF6+EasyUI 后台管理系统(51)-系统升级

    系统很久没有更新内容了,期待已久的更新在今天发布了,最近花了2个月的时间每天一点点,从原有系统 MVC4+EF5+UNITY2.X+Quartz 2.0+easyui 1.3.4无缝接入 MVC5+E ...

  9. ASP.NET MVC5+EF6+EasyUI 后台管理系统(58)-DAL层重构

    系列目录 前言:这是对本文系统一次重要的革新,很久就想要重构数据访问层了,数据访问层重复代码太多.主要集中增删该查每个模块都有,所以本次是为封装相同接口方法 如果你想了解怎么重构普通的接口DAL层请查 ...

  10. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理

    这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...

随机推荐

  1. 信息资源管理综合题之“什么是公钥基础设施(PKI) 和 PKI的任务核心 和 补全PKI认证服务系统流程图”

    一.关于公钥基础设施(PKI),请回如下问题 1.PKI的核心任务是什么? 2.PKI的任务核心是什么? 3.基于PKI的认证服务系统至少由哪几部分组成?请将答案内容(1)~(5)填写在题中图下对应的 ...

  2. python存储MongoDB数据

    MongoDB是由C++语言编写的非关系型数据库,是一个基于分布式文件存储的开源数据库系统,其内容存储形式类似JSON对象,它的字段值可以包含其他文档.数组及文档数组,非常灵活(总体来看,python ...

  3. IP到国家代码映射之GeoLite2导入到MySQL形成数据字典

    一.准备CSV文件与MySQL表结构‌ ‌下载并解压GeoLite2-Country-CSV数据‌ 从 MaxMind 下载 GeoLite2-Country-CSV.zip,解压后获取以下文件: G ...

  4. unbuntu离线部署K8S集群

    环境准备和服务器规划部署前提已知条件: 环境准备与服务器规划总表 类别 配置项 详细信息 操作系统 版本 Ubuntu 25.04(所有节点) 容器运行时 Docker 版本 Docker 24.0. ...

  5. 基于小熊派Hi3861鸿蒙开发的IoT物联网学习【六】--智慧农业MQTT数据上传华为云

    本示例将在BearPi-HM_Nano开发板上使用MQTT协议连接华为IoT平台,使用的是E53_IA1 智慧农业扩展板与 BearPi-HM_Nano 开发板.   E53_IA1开发板对应方法: ...

  6. System.currentTimeMillis()高并发性能优化

    摘要:System.currentTimeMillis()性能问题的研究.测试与优化.   性能优化使用的测试环境: jdk版本jdk8   操作系统: macOS 版本:13.2.1 芯片: App ...

  7. 洛谷 P3792 由乃与大母神原型和偶像崇拜

    洛谷 P3792 由乃与大母神原型和偶像崇拜 Problem 糖果屋的故事讲的就是韩赛尔和格雷特被继母赶出家里,因为没饭吃了,然后进了森林发现了一个糖果屋,里面有个女巫,专门吃小孩子 然而如果我们仔细 ...

  8. 「Note」字符串方向 - 自动机相关

    1. AC 自动机 ACAM 1.1. 简介 AC 自动机用于解决多模式串匹配问题,例如求多个模式串在文本串中的出现次数.显著地,它的应用实际上非常广泛. 借助 KMP 的思想,我们对 Trie 树上 ...

  9. 关于学习率-----linearLR

    1. lr_scheduler综述 torch.optim.lr_scheduler模块提供了一些根据epoch训练次数来调整学习率(learning rate)的方法.一般情况下我们会设置随着epo ...

  10. ceph对象存储

    一.Ceph对象存储的概念 ceph是一种分布式对象存储系统,通过ceph对象网关提供对象存储接口,也称为RADOS网关(RGW)接口.它构建在Ceph RADOS之上.RGW使用librgw(RAD ...