C# EntityFramwork(Model First)使用要点
本文介绍EntityFramework使用方法
Entity Framework的注意点
由于安装和操作的细节讲起来很琐碎,这部分只罗列出难点,其他细节请自行查阅
安装细节
Pluralize or singularize generated object names(确定所生成对象名称的单复数形式)复选框
此复选框的意思是,将数据库中的复数表名映射成单数形式的实体类,如果有一对多,多对多关系的表会将属性名以复数形式显示,增加程序可读性
Include foreign key columns in the model (在模型中包含外键)复选框
将数据库外键关系映射到实体模型中
Import selected stored procedures and functions into entity model (将所选存储过程和函数导入到实体模型中)
将存储过程和函数导入到实体模型
操作CRUD
要先实例化上下文类
using(var ctx = new SchoolDBEntities())
{
// 进行增删改查
}
支持的查询方法
支持的查询数据的方式有
LINQ to Entites
linq方法
var linq = ctx.Students.Where(s => s.StudentID > 2);
linq查询语句
var linq = from item in ctx.Students select item;
Entity SQL
此法不建议使用
Native SQL
var tempResult = ctx.Students.SqlQuery("select * from Student");
注意:sql语句返回的列不能改名,否则报错
返回值类型的写法
string result = db.Database.SqlQuery<string>("select studentname from Student where studentid = 1").FirstOrDefault<string>();
执行非查询sql的写法
int noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update student set studentname ='changed student by command' where studentid=1");
ef表示体包含的方法
ctx.Students表实体中除了上面讲到的SqlQuery方法外还包括如下方法
Add方法
db.Students.Add(student); // 添加一条记录到实体框架中
AsNoTracking方法
如果查询的数据只是用来展示的,可以使用AsNoTracking方法将查询的数据和DbContext断开连接,提高查询效率
var result = db.Students.Select(s => new
{
s.StandardId,
s.StudentName
}).AsNoTracking().ToList();
Attach方法
将一条Student数据附加到EF的跟踪图中就像数据是从数据库中读取的一样,其实数据库中并不存在
var result = db.Students.Attach(st);
Create方法
创建一个空的Student实例,该实例没有附加到Students集合中
var result = db.Students.Create();
Find方法
返回Students表中主键id是5的数据,与之关联的数据也会一起返回
如果数据已经添加到上下文中,但是没有保存到数据库,使用Find同样有效
var result = db.Students.Find(5);
Include方法
指定包含在结果集中的导航属性
var result = db.Students.Include("StudentAddress").ToList<Student>();
也可以传递lambda表达式
var result = db.Students.Include(s => s.Standard).ToList<Student>();
Remove方法
将提供的Student实例标记为已删除,改实例必须存在于上下文中
var result = db.Students.Remove(st);
SqlQuery带参数的用法
var result = db.Students.SqlQuery("select * from student where studentid = @p", new SqlParameter("@p", SqlDbType.Int) { Value = 5} ).Select(s => s.StudentName).ToList();
DBEntityEntry对象
ef实体框架中,可以通过数据实体获取数据实体相关的DBEntityEntry对象,从而得到数据实体的所有信息
var student = db.Students.Find(1);
student.StudentName = "yejiawei";
var entry = db.Entry(student); // 获取数据实体的DBEntityEntry对象
属性
var result = entry.Entity.GetType().FullName; // 获取实体的名称
var result = entry.State.ToString(); // 获取实体当前的状态
IEnumerable<string> result = entry.CurrentValues.PropertyNames; // 获取实体的所有属性名
var result = entry.OriginalValues["StudentName"]; // 获取实体属性修改之前的值
var result = entry.CurrentValues["StudentName"]; // 获取实体属性修改之后的值
可以手动设置实体的状态为 Added,Modified,Deleted
entry.State = EntityState.Modified;
方法
Collection
返回导航属性的集合,多对多关系
var result = entry.Collection("Courses");
可以继续使用 result.Load() 预载数据
还可以继续使用 result.Query().Where(...) 进一步筛选数据
ComplexProperty
返回复杂属性的集合
GetDatabaseValues
返回跟踪的属性集合
var result = entry.GetDatabaseValues();
Property
返回实体指定属性的所有信息组成的集合
var result = entry.Property("StudentName");
Reference
返回导航属性的集合,一对多或者多对一关系
var result = entry.Reference("StudentAddress");
可以继续使用 result.Load() 预载数据
还可以继续使用 result.Query().Where(...) 进一步筛选数据
Reload方法
entry.Reload();
调用此方法,之前的所有更改都无效,全部和数据库同步,并且当前状态是Unchanged
追踪变化
在ef上下文的生命周期中,ef会自动追踪加载进来的实体,可以通过ChangeTracker来获取所有被上下文追踪的实体
每一个实体都必须包含一个主键,如果没有主键ef是不会追踪的
var student = db.Students.Find(1);
属性
var result = db.ChangeTracker.Entries(); // 获取所有被上下文追踪的实体
var result = db.ChangeTracker.Entries().Count(); // 获取所有被上下文追踪的实体的个数
var result = db.ChangeTracker.Entries(); // 获取当前上下文中的所有DBEntityEntry对象对象
维持Entity Framework的实体场景
连接场景
数据检索和增删改都在一个上下文里面操作
在连接场景中完成增删改查是非常容易的,因为上下文自动跟踪实体的状态,AutoDetectChangesEnabled默认是true
添加操作
定义一个引用类型比较类
public class StudentComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
if (x.StudentName.ToLower() == y.StudentName.ToLower())
{
return true;
}
return false;
}
public int GetHashCode(Student obj)
{
return obj.GetHashCode();
}
}
新增操作
if(!db.Students.ToList().Contains(new Student() { StudentName = "yejiawei" }, new StudentComparer()))
{
db.Students.Add(new Student() { StudentName = "yejiawei" });
db.SaveChanges();
return Ok("添加成功");
}
return Ok("已经存在了");
修改操作
Student StudetUpdate = db.Students.ToList().Where(s => s.StudentName == "yejiawei").FirstOrDefault();
StudetUpdate.StudentName = "叶家伟";
db.SaveChanges();
删除操作
db.Students.Remove(db.Students.ToList().ElementAt(0));
db.SaveChanges();
断开连接场景
数据检索和增删改在不同的上下文里面操作
在断开连接场景中,我们需要附加实体到新的上下文中,并且要指定状态
Add方法,会自动的将实体块附加到新的上下文中并且自动的修改状态为Added,也就是说你调用Add方法,管他啥玩意儿都可以成功
Attach方法,调用Attach方法会将实体块添加到上下文中,但是状态还是Unchanged,需要手动设置
var test = db.Students.Attach(new Student() { StudentName = "yejiawei" });
db.Entry(test).State = EntityState.Added;
var result = db.Entry(test).State.ToString();
db.SaveChanges();
单个的实体
单个的实体,直接更改状态,然后保存即可
var test = new Student() { StudentName = "叶家伟" };
db.Entry(test).State = EntityState.Added;
var result = db.Entry(test).State.ToString();
db.SaveChanges();
Entity Framework并发问题
在ef中可以根据数据库timestamp类型的列来处理并发问题,timestamp数据会在插入和更新时自动更改并且是唯一的
数据库中timestamp类型的值是自动添加的
然后,需要在ef中将timestamp列属性中的Concurency Mode设置为Fixed
此时,ef在执行更新操作会将timestamp列设置成where的字句,来判断操作的数据有没有并发操作,如果发生了并发操作,那么会抛出DbUpdateConcurrencyException错误
Student test1 = null;
using(var context1 = new SchoolDBEntities())
{
context1.Configuration.ProxyCreationEnabled = false; // 查询的时候是否包含导航属性
test1 = context1.Students.Where(s => s.StudentID == 9).Single();
test1.StudentName = "小王";
try
{
context1.Entry(test1).State = EntityState.Modified;
context1.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
var t = ex;
}
}
执行存储过程
如下的存储过程导入到ef中
ALTER PROCEDURE [dbo].[GetCoursesByStudentId]
-- Add the parameters for the stored procedure here
@StudentId int = null
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
select c.courseid, c.coursename,c.Location, c.TeacherId
from student s left outer join studentcourse sc on sc.studentid = s.studentid left outer join course c on c.courseid = sc.courseid
where s.studentid = @StudentId
END
然后直接当做函数执行就可以了
var courses = db.GetCoursesByStudentId(1);
可以将更新,删除,新增的存储过程映射到实体上面,从而重写ef默认的增删改的方法
存储过程中,新增的时候执行SELECT SCOPE_IDENTITY() AS StudentId,可以返回新增数据的id
在ef中使用枚举
数据库中可以使用一些特殊的整数值,来表示数据的特殊含义,为了是代码的可读性更强,使用枚举来代替这些整数值
首先,将实体中的一个属性列,Convert to Enum
然后,在弹出的选择框中,输入枚举类型的名字,也就是你在写代码时要用到的枚举名称
其次,在成员列表中,指定成员的名字,和成员对应的整数值
现在,你可以使用你定义的枚举了
var type = TeacherType.Guest;
在ef中使用表值函数
首先要在数据库中添加一个表值函数
ALTER FUNCTION [dbo].[GetCourseListByStudentID]
(
-- Add the parameters for the function here
@studentID int
)
RETURNS TABLE
AS
RETURN
(
-- Add the SELECT statement with parameter references here
select c.courseid, c.coursename,c.Location, c.TeacherId
from student s left outer join studentcourse sc on sc.studentid = s.studentid left outer join course c on c.courseid = sc.courseid
where s.studentid = @studentID
)
然后将这个表值函数导入到ef中,可以在模型浏览器中修改函数,然后在ef中使用表值函数,如下
var result = db.GetCoursesByStudentId(1).Select(s => s);
Local属性
可以通过Local属性访问当前被追踪的实体,被标记为Deleted的实体不可以通过Local访问
db.Students.Load(); // 预载,免去写ToList
db.Students.Add(new Student() { StudentName = "New Student" });
return Ok(db.Students.Local);
预先加载
使用Include,表示加载导航属性
(from s in context.Students.Include("Standard")
where s.StudentName == "Student1"
select s).FirstOrDefault<Student>();
懒加载
当实体中包含包含复杂属性,只有当访问这个复杂属性的时候才会去查询
如果要为整个上下文关闭懒加载,可以在上下文的类中设置
public SchoolDBEntities(): base("name=SchoolDBEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}
如果想只关闭某一个属性的懒加载,可以导实体的类中设置
public virtual StudentAddress StudentAddress { get; set; }将这个virtual关键字去掉即可
异步查询和保存
异步查询
使用async标记此方法是异步的
public async Task<Student> GetStudents()
{
Student result = null;
using (var context = new SchoolDBEntities())
{
context.Configuration.ProxyCreationEnabled = false;
// 使用await,可以释放当前线程从而可以执行其他代码,避免阻塞程序
result = await context.Students.Where(s => s.StudentID == 10).FirstOrDefaultAsync<Student>();
}
return result;
}
异步保存
public async Task<int> Get()
{
using (var context = new SchoolDBEntities())
{
var test = context.Courses.Attach(new Course() { CourseName = "数学" });
context.Entry(test).State = EntityState.Added;
return await context.SaveChangesAsync();
}
}
日志的记录
第一种方式,使用默认配置
在web.config配置文件中的entityFramework节点下添加
<interceptors>
<interceptor type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework">
<parameters>
<parameter value="F:\学习实验区\EntityFramework\Log.txt"/>
<parameter value="true" type="System.Boolean"/>
</parameters>
</interceptor>
</interceptors>
即可自动的记录ef做的所有操作
第二种方式,自定义日志记录
using (var context = new SchoolDBEntities())
{
// 使用Log方法即可自动实现记录日志,然后追加到日志文件中
context.Database.Log = (string message) =>
{
byte[] bts = Encoding.UTF8.GetBytes(message);
using (FileStream fwrite = File.OpenWrite(@"F:\学习实验区\EntityFramework\Log1.txt"))
{
//fwrite.Write(bts, 0, bts.Length);
fwrite.Position = fwrite.Length;
fwrite.Write(bts, 0, bts.Length);
}
};
var test = context.Courses.Attach(new Course() { CourseName = "数学" });
context.Entry(test).State = EntityState.Added;
return await context.SaveChangesAsync();
}
事务提交和回滚
ef默认的操作都是事务处理的,但是我们可以将ef多个操作再用一个事务封装起来,方便回滚
using(DbContextTransaction dbTran = context.Database.BeginTransaction())
{
try
{
var test = context.Courses.Attach(new Course() { CourseName = "333" });
context.Entry(test).State = EntityState.Added;
await context.SaveChangesAsync();
dbTran.Commit();
return 1;
}catch(Exception ex)
{
dbTran.Rollback();
return 0;
}
}
AddRange和RemoveRange
AddRange批量增加
List<Course> list = new List<Course>()
{
new Course() { CourseName = "yuwen" },
new Course() { CourseName = "shuxue" },
new Course() { CourseName = "yinyu" }
};
using (var context = new SchoolDBEntities())
{
context.Courses.AddRange(list);
return await context.SaveChangesAsync();
}
RemoveRange批量删除
using (var context = new SchoolDBEntities())
{
var items = context.Courses.Where(
s => s.CourseName == "yuwen" || s.CourseName == "shuxue" || s.CourseName == "yinyu"
).AsEnumerable<Course>();
context.Courses.RemoveRange(items);;
return await context.SaveChangesAsync();
}
C# EntityFramwork(Model First)使用要点的更多相关文章
- A Neural Probabilistic Language Model (2003)论文要点
论文链接:http://www.jmlr.org/papers/volume3/bengio03a/bengio03a.pdf 解决n-gram语言模型(比如tri-gram以上)的组合爆炸问题,引入 ...
- Efficient Estimation of Word Representations in Vector Space (2013)论文要点
论文链接:https://arxiv.org/pdf/1301.3781.pdf 参考: A Neural Probabilistic Language Model (2003)论文要点 https ...
- 关于DOM树的常见增删操作
//具体关于DOM的内容可参考我的另外一篇文章"文本对象模型(Document Object Model)". 案例要点: 1.创建并增加元素节点 2.判断是否存在 ...
- Spring Boot笔记一
Spring Boot 入门 Spring Boot 简介 > 简化Spring应用开发的一个框架:> 整个Spring技术栈的一个大整合:> J2EE开发的一站式解决方案: 微服务 ...
- [php]laravel框架容器管理的一些要点
本文面向php语言的laravel框架的用户,介绍一些laravel框架里面容器管理方面的使用要点.文章很长,但是内容应该很有用,希望有需要的朋友能看到.php经验有限,不到位的地方,欢迎帮忙指正. ...
- Java Web编程技术学习要点及方向
学习编程技术要点及方向亮点: 传统学习编程技术落后,应跟著潮流,要对业务聚焦处理.要Jar, 不要War:以小为主,以简为宝,集堆而成.去繁取简 Spring Boot,明日之春(future of ...
- Mysql –>EF edmx(model first)–> Sql server table
一.mysql environment When we create an new database,first We need draw er diagram for somebody to sho ...
- Neutron LBaaS Service(2)—— Neutron Services Insertion Model
Service Insertion Service Insertion是Neutron中实现L4/L7层服务的框架.Neutron以前只有一级插件结构用于实现各种L2层技术(如LinuxBridge, ...
- 一个多阶段库存订货问题的 +Leapms 求解要点
一个多阶段库存订货问题的 +Leapms 求解要点 问题来自微信公众号“运筹分享交流”——“互助·运筹擂台3 多阶段库存订货问题”. 数学概念模型 求解结果 +Leapms>mip relexe ...
随机推荐
- ZooKeeper服务-一致性、实现
实现 ZooKeeper服务有两种不同的运行模式.一种是“独立模式”(standalone mode),即只有一个ZooKeeper服务器.这种模式比较简单,适合于测试环境,但是不能保证高可用性和可恢 ...
- Java内部锁的可重用性(Reentrancy)
Java提供了强制原子性的内部锁机制:synchronized块.但是内部锁是可重入的,当线程试图获得它自己占有的锁时,请求会成功. 简单的说,就是在一个synchronized方法内部调用本类的其他 ...
- STL视频_00
[05:40]比赛规则 - Part01[06:33]比赛规则 - Part02[07:28]比赛规则 - Part03[08:45]提出的问题 - 1和2[09:23]提出的问题 - 3和4 *** ...
- write.table函数语法:
write.table (x, file ="", sep ="", row.names =TRUE, col.names =TRUE, quote ...
- Python爬虫之BeautifulSoup的用法
之前看静觅博客,关于BeautifulSoup的用法不太熟练,所以趁机在网上搜索相关的视频,其中一个讲的还是挺清楚的:python爬虫小白入门之BeautifulSoup库,有空做了一下笔记: 一.爬 ...
- substr 方法
substr 方法 返回一个从指定位置开始,并具有指定长度的子字符串. 参数 start 必选.所需的子字符串的起始位置.字符串中第一个字符的索引为 0. length 可选项.返回的子字符串中包含的 ...
- 51nod 1428 贪心
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1428 1428 活动安排问题 基准时间限制:1 秒 空间限制:13107 ...
- JVM_总结_01_JDK的安装
一.前言 本文主要简要介绍下JDK的安装 二.下载 1.JDK下载地址 前往官方网站下载JDK jdk8官网下载 2.JDK下载 如下图 下载完之后得到安装软件,如下图 三.安装 双击运行安装软件,即 ...
- L124
I have a toothache because there is a cavity in one of my teeth. I founded an orphanage last year an ...
- SQLAlchemyの增删改查
用a*my写原味sql from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, I ...