Entity Framework

EF的简介,使用,EF添加,删除,修改数据,EF查询延迟加载,MdoleFirst,EF的导航属性

Entity Framework

Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (ORM,对象关系对应) 解决方案。只要涉及要数据处理都可以使用EF。

如何使用EF

在项目中新建项,点击数据,选择ADO.NET实体数据模型,以VS2017为例,选择模型内容,视你ModleFirst还是DateBaseFirst(下面以来自数据库设计),新建链接(连接字符串包含密码等敏感词),下一步选择EF6,选择数据库对象的时候的表选择你想要操作的表

关于NuGet包

引用NeGet包,右键项目引用——管理NeGet包,就会自动引用对应Dll.比如说要引用一个第三方的Dll或者第三方工具,我们都可以在NuGet直接搜索就可以了,方便版本升级。

如何使用EF添加数据

我们可以找到对应的数据库模型(modle)类,可以简单的new它出来,给它相关的属性赋值,然后找到

context.cs(上下文)**,可以发现一个跟项目名称差不多但是后面加上Entities(也不一定,但是基本你能立刻找到),比如EfFirstModleEntities这个类,这个类就是用来操作数据的类**

1
2
3
4
5
6
7
8
9
10
11
12
13
//简单的点击一个按钮添加到数据库
protected void Button1_Click(object sender, EventArgs e)
{
UserInfo userInfo = new UserInfo();
userInfo.Email = "6223232993@qq.com";
userInfo.RegTime = DateTime.Now;
userInfo.UserName = "kju127";
userInfo.UserPwd = "123456";
EfFirstModleEntities ef = new EfFirstModleEntities();
ef.UserInfo.Add(userInfo);//将数据添加到EF并且添加了添加标记
ef.SaveChanges();//数据才会保存到数据库,返回受影响的行数
Response.Write(userInfo.Id);//这里会输出插入生成的id,说明当执行的sql语句中带有查询语句,然后赋值给之前声明的对象
}

上面的EF操作类点出的userinfo属性是一个集合,可以使用它进行增删改查

1
public virtual DbSet<UserInfo> UserInfo { get; set; }

可以利用sqlserver工具选项里面的profiler工具捕获生成的sql语句如下

1
2
3
4
5
INSERT [dbo].[UserInfo]([Email], [RegTime], [UserName], [UserPwd])
VALUES (@0, @1, @2, @3)
SELECT [Id]
FROM [dbo].[UserInfo]
WHERE @@ROWCOUNT > 0 AND [Id] = scope_identity()',N'@0 nvarchar(50),@1 datetime2(7),@2 nvarchar(50),@3 nvarchar(50)',@0=N'6223232993@qq.com',@1='2018-03-12 01:53:33.7243611',@2=N'kju127',@3=N'123456'

其中**@@ROWCOUNT**系统关键字,返回上次sql语句所影响的数据行数要>0。

scope_identity()**函数,返回插入到同一作用域中的标识列内的最后一个标识值,这里要注意SCOPE_IDENTITY 和 @@IDENTITY返回在当前会话中生成任何表中的最后一个标识值。 但是,SCOPE_IDENTITY 返回仅在当前作用域; 中插入值@@IDENTITY并不局限于特定的作用域。因此我们尽量使用SCOPE_IDENTITY。**

例如,有两个表 T1 和 T2,T1有两条数据,T2有三条,并且在 T1 上定义了 INSERT 触发器。 当将某行插入 T1 时,触发器被激发,并在 T2 中插入一行。使用Scope_identity () 返回在 T1 中插入的标识值即3。使用@@IDENTITY返回4.两者作用域不一样。

EF查询延迟加载

首先我们看下面这张图了解EF的机制,应用程序构建好数据,把数据交给DBContext,DbContext

读取Xml文件找到实体和表的映射关系,生成对应sql语句交给数据库执行

22Z4Oe.png

何为查询延迟加载,先看下面一段简单代码,有关linq学习:https://www.cnblogs.com/xiashengwang/archive/2012/07/28/2609161.html

1
2
3
4
5
6
7
8
9
10
11
12
protected void Button2_Click(object sender, EventArgs e)
{
//使用linq查询
EfFirstModleEntities ef = new EfFirstModleEntities();
var sqlStr = from u in ef.UserInfo //类型等同IQueryable<UserInfo>,继承自IEnumerable<T>因此可以使用foreach
where u.Id == 1
select u;
foreach (UserInfo userInfo in sqlStr)
{
Response.Write(userInfo.UserName);
}
}

只有当执行到foreach中的in,即查询查询数据时,才会执行linq的查询语句,这样一来能保证性能

EF删除数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected void Button3_Click(object sender, EventArgs e)
{
EfFirstModleEntities ef = new EfFirstModleEntities();
var sqlStr = from u in ef.UserInfo
where u.Id == 2
select u;
UserInfo user=sqlStr.FirstOrDefault();//返回第一个元素如果没有则返回null
if (user!=null)
{
ef.UserInfo.Remove(user);
//ef.Entry(user).State = EntityState.Deleted; 这样也相当于添加删除标记
ef.SaveChanges();
}
else
{
Response.Write("无法删除不存在的数据!!!");
}

//还可以这样,用这种比较好
//UserInfo userInfo = new UserInfo() { Id = 2 };
//ef.Entry(userInfo).State = EntityState.Deleted;
//ef.SaveChanges();//如果不存在ID=2那么将会报错
}

EF修改数据以及MdoleFirst

1
2
3
4
5
6
7
8
EfFirstModleEntities ef = new EfFirstModleEntities();
var strSql = from u in ef.UserInfo
where u.Id == 2
select u;
UserInfo userInfo = strSql.FirstOrDefault();
userInfo.UserPwd = "6666666"
ef.Entry(userInfo).State = EntityState.Modified;
ef.SaveChanges();

MdoleFirst,即要创建一个空的实体数据模型,然后右键-新增-实体,默认的创建属性时ID,且时主键并且自增。

选中你创建好的实体模型右键-新增标记属性,记住如果时string类型的话必须制定长度,不然默认是max。

!!!注意这时候如果你发现没有tt文件,在空白处右键-添加代码生成项!!!

在创建多个实体模型之后,右键-新增-关联,弹出来的面板,可以让你选择一对多或者多对多的关系,导航属性不要去掉,表示两者有关联,可以通过导航属性查询,下面的添加外键属性通常也是要的。其实多对多是两个表多对多,中间得再增加一个表,通多这个表来表现多对多,表中数据那就他们两个表的id

22IaTL.png

在空白处右击根据模型生成数据库,生成一个ddl文件,在生成的文件右键执行,这样一来就在数据库生成相应的表了,另外如果主键是GUID的话会比ID插入要快,ID的自增是查询表中最大的,然后锁住,插入的时候+1

要注意进行二次开发的话,那么就得注意不能直接执行生成的ddl文件,因为这样会直接操作删除数据库或者其他对现存数据库有很大影响的操作,慎重,如果只是简单的修改表的属性可以直接操作数据库即可

EF导航属性的应用

上面我们提到导航属性,具体的应用如何,先看下面一段代码(模型对象沿用上面的两个,customer和orderinfo),添加数据

1
2
3
4
5
6
7
8
9
10
11
protected void Button4_Click(object sender, EventArgs e)
{
Model2Container db = new Model2Container();
Customer customer = new Customer(){Name = "张三",Pwd = "123",ReageTime = DateTime.Now};
OrderInfo order1 = new OrderInfo(){Customer = customer,CreatDateTime = DateTime.Now,OrderNum = "10000"};
OrderInfo order2 = new OrderInfo(){Customer = customer,CreatDateTime = DateTime.Now,OrderNum = "10001"};
db.CustomerSet.Add(customer);//必须先插入customer,这里就是用到导航属性
db.OrderInfoSet.Add(order1);
db.OrderInfoSet.Add(order2);
db.SaveChanges();//封装的这个方法默认开启了事务
}

上面就保存了一段数据,可以看到我们指定了订单的客户。数据库只连接了一次,用到工作单元的设计模式(简单说就是把要查询的语句放进一个集合里面,然后依此执行这样一来就只连接一次数据库)。

查询客户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void Button5_Click(object sender, EventArgs e)
{
Model2Container db = new Model2Container();
var customerList = from customer in db.CustomerSet
select customer;
foreach (Customer customer in customerList)
{
Response.Write(customer.Name+ ":\n");
foreach (OrderInfo orderInfo in customer.OrderInfo)
{
Response.Write(orderInfo.OrderNum+"\n");
}
}
}

结果

1
张三: 10000 10001

这样一来是用了查询两次


Entity Framework
http://www.kju147.com/2018/04/15/Entity-Framework/
作者
个人学习
发布于
2018年4月15日
许可协议