webapi框架搭建-数据访问ef code first
webapi框架搭建系列博客
为什么用ef?
我相信很多博友和我一样都有这种“选择困难症”,我曾经有,现在也有,这是技术人的一个通病——总想用“更完美”的方式去实现,导致在技术选择上犹豫不决,或总是推翻别人的技术路线,甚至屡屡推翻自己从前的想法,这种专研的精神固然不错,但随着年龄的增大,会发现这种习惯已将自己弄得很累,其实真没有必要。我觉得技术上永远没有“完美”的解决方案,如果揪着缺点去比较和选择,不管最终选择了什么,以后都会后悔。因为你总是看到它身上的缺点。orm的框架也有很多,大家都说entityframework性能有点差,它生成的sql语句简直看不下去,我也考虑过dapper,但它要写一些sql语句,这不是我想干的事(纯属个人代码风格偏好)。分享下为什么会选择ef。我的orm框架的要求是这样的:1、简单快速上手(因为我不太想将太多的精力花在这上面,而ef各方法的资料还是很全的);2、性能只要过得去就行(又不是要开发对性能要求很苛刻的产品,我想微软的产品也不至于性能很低吧);3、后面如果要换数据库,最好不要改代码(这点是我喜欢ef的主要原因,只要将数据连接换一下,dll包换一下,数据库就可以从mysql,sqlserver,oracle任意切换)
为什么用code first?
1、代码简洁
相比db first,code first的代码更简洁,基本所有的代码都是真正需要的。而db first有很多自动生成的辅助型的代码。
2、编写简单
db first在sqlserver下也简单,但如果是mysql或是oracle,在vs的配置上就会遇到很多问题,我初学时经常遇到vs连mysql失败,或是连接成功后总是生成代码时失败。而用code first,你只要写实体的代码就行,虽然是”多写了一些代码“,但其实速度上比db first还是快的。
参考资料
推荐:http://www.entityframeworktutorial.net/code-first/entity-framework-code-first.aspx
微软官方:https://msdn.microsoft.com/en-us/library/aa937723(v=vs.113).aspx
下面介绍如何实用
用法和步骤
引用相关包
如果是sqlserver数据库,只要引用entityframework就行
如果是mysql数据库,引用mysql.data.entity包(依赖mysql.data包)
注意:在实际开发中发现有些版本的mysql.data.entity包是有bug的,如版本6.10.5,建议安装6.9.10(测试没有问题)
如果是oracle数据库,引用oracle.managedDataAccess.EntityFramework包(依赖Oracle.ManagedDataAccess包)
oracle注意:微软也出过oracle的连接库,但不支持ef,现在都提倡用oracle出的odp.net技术。而odp.net以前的版本是基于oracle.dataaccess.dll的,这个有x86和x64位之分,开发时很不方便,建议用oracle.managedDataAccess.dll.
引用包后,会在web.config里自动生成如下相应的配置信息:
1)在configuration--》configSections节点下面生成名为entityFramework的section
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
2)
编写实体类
如下代码
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema; namespace webapi.Entities
{
[Table("Test")]
public class TestTable
{
[Key,Column(TypeName = "varchar"),MaxLength(50)]
public string Id { set; get; }
[Column(TypeName = "int")]
public int? Age { set; get; }
[Column(TypeName = "datetime")]
public DateTime? CreateDateTime { get; set; }
}
}
实体通过dataannotations的方式描述在数据库里类型,长度、主键等。没有必要死记他们的写法,不会时参考http://www.entityframeworktutorial.net/code-first/stringlength-dataannotations-attribute-in-code-first.aspx就行。
编写数据库上下文
1)创建继承自DbContext的类
using System.Data.Entity; namespace webapi.Entities
{
public class DB : DbContext
{
/// <summary>
/// name=DBConnection,DBConnection为数据库连接的名字,即web.config配置文件节点connectionStrings,name值为DBConnection的数据库连接字符串
/// </summary>
public DB()
: base("name=DBConnection")
{
} #region 配置所有的数据库表 public DbSet<TestTable> TestTables { set; get; } #endregion }
}
2)在web.config里配置数据库连接字符串
由于数据库连接字符串比较重要,为方便,在实际的开发中经常单独配置在一个文件里,然后在web.config里去引用配置文件。
创建ConnectionStrings.config文件,内容如下
<?xml version="1.0" encoding="utf-8"?>
<connectionStrings>
<!--sqlserver连接字符串-->
<!--<add name="DBConnection" providerName="System.Data.SqlClient" connectionString="Data Source = localhost; Initial Catalog = WebApiFramework; User Id = sa; Password = 1" />-->
<!--mysql连接字符串-->
<add name="DBConnection" providerName="MySql.Data.MySqlClient" connectionString="Data Source=localhost;Initial Catalog=webapi;User id=root;Password=root;charset=utf8;port=3306;" />
<!--oracle连接字符串-->
<!--<add name="DBConnection" providerName="Oracle.ManagedDataAccess.Client" connectionString="Data Source=localhost;User Id=system;Password=root;" />-->
</connectionStrings>
上面将常用的数据库的连接方式举例出来,以后要换数据库,只要按一下数据库的连接字符串就行。
编写测试接口
code first的基本来法就上面三步了。我们来测试下是否正常。
1)创建测试接口,代码如下:
using System.Linq;
using System.Web.Http;
using webapi.Entities; namespace webapi.example
{
public class EFTestController : ApiController
{
public IHttpActionResult Get()
{
using (DB db=new DB())
{
var list = db.TestTables;
return Ok(list.ToList());
}
}
}
}
2)运行接口
用postman访问接口地址(get方法):http://localhost:101/api/EFTest,返回结果为空json数组:[];
注意:我的电脑上已经安装了mysql,但并没有webapi数据库啊,为什么接口正常运行呢?原因是entityframework会自动检测是否存在数据库,如果没有就会去创建。下面是ef自动创建的数据库
注意到数库里还自动生了了”_MigrationHistory"的表,它有什么用处呢?先说下几个例子
(1)如果现在在TestTable实体里增加一个数据库对应的字段,或是在数据库表里增加一个字段,编译后再访问上面同样的接口,会出现下面的错误
{
"Message": "The model backing the 'DB' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269)."
}
(2)如果在(1)的操作后,删除了_MigrationHistory表再访问接口,同样会报错,但错误的内容已经变成如下
Unknown column 'Extent1.AddColumn' in 'field list'
(3)如果在(2)的操作后,删除TestTable实体在(1)中增加的字段,再次访问接口时会运行成功
_MigrationHistory作用总结:用于比较model和数据库的版本是否一致,如果不一致则报(1)中的错误,不会执行sql语句;如果这个表没有,就不会进行model和数据库的版本检测,直接执行ef生成的sql语句。code first在目标数据库没有的情况下会创建数据库,并创建_MigrationHistory表,也可以用于连接已经存在数据库(此时目标数据库里可能没有_MigrationHistory),但这时要确保自己的实体和目标数据库的表是一样的。
增加Migration机制
Migration即是将model的更改应用到数据库里,分自动和手动两种机制,具体可参考http://www.entityframeworktutorial.net/code-first/migration-in-code-first.aspx。
1)在vs的程序包管理器控制台里运行enable-migrations –EnableAutomaticMigration:$true
如果是mysql数据库,可能会出现如下错误:
Checking if the context targets an existing database...
No MigrationSqlGenerator found for provider 'MySql.Data.MySqlClient'. Use the SetSqlGenerator method in the target migrations configuration class to register additional SQL generators.
原因:codefirst默认是生成sqlserverr的sql语句,要在migrations的配置代码里改成用mysql 。此时在项目里已经成功生成了Migrations文件夹,里面有个Configurations.cs类,修改Configurations.cs代码,如下
using System.Configuration; namespace webapi.Migrations
{
using System.Data.Entity.Migrations; internal sealed class Configuration : DbMigrationsConfiguration<webapi.Entities.DB>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;//自动更新数据库
AutomaticMigrationDataLossAllowed = true;//重命名和删除表字段时会丢失数据,设置成允许,否则此情况下同步数据库会出错
var providerName = ConfigurationManager.ConnectionStrings["DBConnection"].ProviderName;
if (providerName == "MySql.Data.MySqlClient")
{
SetSqlGenerator("MySql.Data.MySqlClient", new MySql.Data.Entity.MySqlMigrationSqlGenerator());//如果数据库用mysql,加上这一句
}
} protected override void Seed(webapi.Entities.DB context)
{
// This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
}
}
}
如果AutomaticMigrationDataLossAllowed不设置成true(默认为false),重命名实体的属性名是会出现如下错误
Automatic migration was not applied because it would result in data loss. Set AutomaticMigrationDataLossAllowed to 'true' on your DbMigrationsConfiguration to allow application of automatic migrations even if they might cause data loss. Alternately, use Update-Database with the '-Force' option, or scaffold an explicit migration.
2)修改数据库上下文的配置
using System.Data.Entity; namespace webapi.Entities
{
public class DB : DbContext
{
/// <summary>
/// name=DBConnection,DBConnection为数据库连接的名字,即web.config配置文件节点connectionStrings,name值为DBConnection的数据库连接字符串
/// </summary>
public DB()
: base("name=DBConnection")
{
// 默认策略为CreateDatabaseIfNotExists,即如果数据库不存在则创建,用migrations时改成MigrateDatabaseToLatestVersion,即每次第一次访问数据库时同步最新的数据库结构
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DB, webapi.Migrations.Configuration>("DBConnection"));
} #region 配置所有的数据库表 public DbSet<TestTable> TestTables { set; get; } #endregion }
}
加入migrations机制后,如果在实体里改变了实体的结构,在第一次网站访问时就会自动去更新数据库的结构,非常方便。
经验:在开发时要避免手动去改数据库的结构,这样会导致各种migrations失败的错误,code first,顾名思义就是让我们以code为先,我们通常修改code的实体间接的去同步数据库结构。手动改数据库那是db first的思想。在项目正式上线还是要慎用migration机制,最好是将AutomaticMigrationDataLossAllowed还原为默认false,不然一个实体的重命名会导致数据库表的数据丢失,切记切记。
webapi框架搭建-数据访问ef code first的更多相关文章
- webapi框架搭建系列博客
webapi框架搭建系列博客 webapi框架搭建-创建项目(一) webapi框架搭建-创建项目(二)-以iis为部署环境的配置 webapi框架搭建-创建项目(三)-webapi owin web ...
- webapi框架搭建-创建项目(三)-webapi owin
上一篇:创建项目(二) 在上一篇里,我们已经创建好了webapi应用,并已经部署到iis里,本篇讲如何用owin自宿主或是iis宿主来部署webapi应用. owin介绍 传统的asp.net网站只能 ...
- webapi框架搭建-创建项目(二)-以iis为部署环境的配置
上篇:webapi快速框架搭建-创建项目(一) 在"创建项目(一)"这一篇里已经创建了一个空的项目,但项目上什么都没有,本篇描述如何将webapi配置成部署在iis上. 步骤 用n ...
- webapi框架搭建-日志管理log4net
前言 本篇讲怎么在前几篇已经创建好的项目里加上日志处理机制,我们采用Log4net技术.跟多的log4net技术的细节请查阅log4net的官网. log4net官网:http://logging.a ...
- webapi框架搭建-安全机制(四)-可配置的基于角色的权限控制
webapi框架搭建系列博客 在上一篇的webapi框架搭建-安全机制(三)-简单的基于角色的权限控制,某个角色拥有哪些接口的权限是用硬编码的方式写在接口上的,如RBAuthorize(Roles = ...
- webapi框架搭建-安全机制(三)-简单的基于角色的权限控制
webapi框架搭建系列博客 上一篇已经完成了“身份验证”,如果只是想简单的实现基于角色的权限管理,我们基本上不用写代码,微软已经提供了authorize特性,直接用就行. Authorize特性的使 ...
- webapi框架搭建-安全机制(一)
本系列博客链接:webapi框架搭建系列博客 前言 webapi接口是开放给外部使用的,包括接口的地址,传参的规范,还有返回结果的说明.正因为接口的开放性,使得接口的安全很重要.试想一下,用抓包工具( ...
- NHibernate:教你如何搭建数据访问层?
NHibernate:教你如何搭建数据访问层? 什么是NHibernate NHibernate 是一个基于.net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Ja ...
- webapi框架搭建-依赖注入之autofac
前言 c#的依赖注入框架有unity.autofac,两个博主都用过,感觉unity比较简单而autofac的功能相对更丰富(自然也更复杂一点),本篇将基于前几篇已经创建好的webapi项目,引入au ...
随机推荐
- LCA(最近公共祖先)算法
参考博客:https://blog.csdn.net/my_sunshine26/article/details/72717112 首先看一下定义,来自于百度百科 LCA(Lowest Common ...
- 程序开发入门工具之CodeBlocks
程序开发基础工具之CodeBlocks 作为程序开发工作者,我们会接触很多的程序开发软件:但实用以及容易掌握的程序开发软件对于初学者的学习能力是有一定的加成的.今天我就作为一个程序开发者给大家推荐一个 ...
- PAT 甲级 1155 Heap Paths
https://pintia.cn/problem-sets/994805342720868352/problems/1071785408849047552 In computer science, ...
- ubuntu 中安装memcache,并给出一个简单的实例·
Memcache分为两部分,Memcache服务端和客户端.Memcache服务端是作为服务来运行的,所有数据缓存的建立,存储,删除实际上都是在这里完成的.客户端,在这里我们指的是PHP的可以调用的扩 ...
- Flexpod的开关机顺序
Flexpod = Cisco UCS + Cisco Nexus + Netapp (中文名叫做“融合基础架构”) 之前没有接触过这套系统,不太明白怎么个开关机的顺序,借公司停电的机会实际演练了一番 ...
- JS 日期 自动补齐 “2017-11-22 14:43”
var myDate = new Date(); var myN = myDate.getFullYear(); var myY = myDate.getMonth(); var myR = myDa ...
- 多示例学习 multiple instance learning (MIL)
多示例学习:包(bags) 和 示例 (instance). 包是由多个示例组成的,举个例子,在图像分类中,一张图片就是一个包,图片分割出的patches就是示例.在多示例学习中,包带有类别标签而示例 ...
- 将javaweb项目部署到阿里云服务器
主要步骤:1. 购买阿里云服务器2. 远程连接3. 在云服务器上配javaweb环境:jdk,tomcat,MySQL4. 将项目的war文件放到Tomcat下关于云服务器ECS:如果还想在买服务器之 ...
- Day 5 笔记 dp动态规划
Day 5 笔记 dp动态规划 一.动态规划的基本思路 就是用一些子状态来算出全局状态. 特点: 无后效性--狗熊掰棒子,所以滚动什么的最好了 可以分解性--每个大的状态可以分解成较小的步骤完成 dp ...
- Sort HDU - 5884(优先队列+二分)
Sort Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submis ...