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的更多相关文章

  1. webapi框架搭建系列博客

    webapi框架搭建系列博客 webapi框架搭建-创建项目(一) webapi框架搭建-创建项目(二)-以iis为部署环境的配置 webapi框架搭建-创建项目(三)-webapi owin web ...

  2. webapi框架搭建-创建项目(三)-webapi owin

    上一篇:创建项目(二) 在上一篇里,我们已经创建好了webapi应用,并已经部署到iis里,本篇讲如何用owin自宿主或是iis宿主来部署webapi应用. owin介绍 传统的asp.net网站只能 ...

  3. webapi框架搭建-创建项目(二)-以iis为部署环境的配置

    上篇:webapi快速框架搭建-创建项目(一) 在"创建项目(一)"这一篇里已经创建了一个空的项目,但项目上什么都没有,本篇描述如何将webapi配置成部署在iis上. 步骤 用n ...

  4. webapi框架搭建-日志管理log4net

    前言 本篇讲怎么在前几篇已经创建好的项目里加上日志处理机制,我们采用Log4net技术.跟多的log4net技术的细节请查阅log4net的官网. log4net官网:http://logging.a ...

  5. webapi框架搭建-安全机制(四)-可配置的基于角色的权限控制

    webapi框架搭建系列博客 在上一篇的webapi框架搭建-安全机制(三)-简单的基于角色的权限控制,某个角色拥有哪些接口的权限是用硬编码的方式写在接口上的,如RBAuthorize(Roles = ...

  6. webapi框架搭建-安全机制(三)-简单的基于角色的权限控制

    webapi框架搭建系列博客 上一篇已经完成了“身份验证”,如果只是想简单的实现基于角色的权限管理,我们基本上不用写代码,微软已经提供了authorize特性,直接用就行. Authorize特性的使 ...

  7. webapi框架搭建-安全机制(一)

    本系列博客链接:webapi框架搭建系列博客 前言 webapi接口是开放给外部使用的,包括接口的地址,传参的规范,还有返回结果的说明.正因为接口的开放性,使得接口的安全很重要.试想一下,用抓包工具( ...

  8. NHibernate:教你如何搭建数据访问层?

    NHibernate:教你如何搭建数据访问层? 什么是NHibernate NHibernate 是一个基于.net 的针对关系型数据库的对象持久化类库.NHibernate 来源于非常优秀的基于Ja ...

  9. webapi框架搭建-依赖注入之autofac

    前言 c#的依赖注入框架有unity.autofac,两个博主都用过,感觉unity比较简单而autofac的功能相对更丰富(自然也更复杂一点),本篇将基于前几篇已经创建好的webapi项目,引入au ...

随机推荐

  1. 用dos命令备份和恢复sql server 数据库

    这里是批处理命令-----备份的 delete d:\restore\cw_ft.bak delete d:\restore\cw_sd.bak sqlcmd -i "bak.sql&quo ...

  2. HTML5+学习笔记2-------边看代码边研究貌似还是有点问题...还在研究中api中

    // 拍照 function getImage() { outSet( "开始拍照:" ); var cmr = plus.camera.getCamera(); cmr.capt ...

  3. 显示所有SAP图标的ABAP代码

    TABLES: icon. INCLUDE <icon>. FIELD-SYMBOLS: <f>. SELECT * FROM icon. ASSIGN (icon-name) ...

  4. 对discuz的代码分析学习(三)mysql驱动

    一. 属性分析         1.tablepre :表名称前缀        2.version : 数据库版本        3.drivertype:驱动类型        4.querynu ...

  5. shell脚本编程常识

    (这些往往是经常用到,但是各种网络上的材料都语焉不详的东西,个人认为比较有用) 七种文件类型 d            目录                                       ...

  6. Windows Server 2008 配置IIS+PHP

    问题: 最近要上线一个PHP写成的MVC项目,发现Windows Server 2008安装的还是PHP5.2,很多语法不支持. 尝试的一些解决方案: 1.将PHP升级为5.6,但是需要做好IIS和P ...

  7. 基于Vue cli生成的Vue项目的webpack4升级

    前面的话 本文将详细介绍从webpack3到webpack4的升级过程 概述 相比于webpack3,webpack4可以零配置运行,打包速度比之前提高了90%,可以直接到ES6的代码进行无用代码剔除 ...

  8. 2018 大湾区(深圳) .NET技术分享交流会 第一期

    .NET Core 2.1 已于2018年5月30日正式发布,邀请粤港澳大湾区.NET技术专家和从业人员,一起分享与交流.NET技术的发展方向,提高粤港澳大湾区.NET技术交流氛围,挖掘.NET高级人 ...

  9. 初次接触Linux

    最近由于工作需求,需要接触Linux系统. 使用VMware虚拟机,安装ubuntu系统.网上教程很多. 配置opencv环境.这是我参考的网上帖子https://blog.csdn.net/fish ...

  10. 微信开发(3):微信公众号发现金红包功能开发,利用第三方SDK实现(转)

    最近需求是 用户兑换微信红包,需要一些验证,加密,以及证书: 工欲善其事必先利其器 感谢前辈的微信SDK 已经维护三年了,还在维护中! 官方文档走一波 文档还是一如既往的 坑人啊,写的很简单,对简单明 ...