webapi框架搭建-数据访问ef code first

webapi框架搭建系列博客

为何用ef?

  我相信不少博友和我同样都有这种“选择困难症”,我曾经有,如今也有,这是技术人的一个通病——总想用“更完美”的方式去实现,致使在技术选择上犹豫不决,或老是推翻别人的技术路线,甚至屡屡推翻本身从前的想法,这种专研的精神当然不错,但随着年龄的增大,会发现这种习惯已将本身弄得很累,其实真没有必要。我以为技术上永远没有“完美”的解决方案,若是揪着缺点去比较和选择,无论最终选择了什么,之后都会后悔。由于你老是看到它身上的缺点。orm的框架也有不少,你们都说entityframework性能有点差,它生成的sql语句简直看不下去,我也考虑过dapper,但它要写一些sql语句,这不是我想干的事(纯属我的代码风格偏好)。分享下为何会选择ef。个人orm框架的要求是这样的:一、简单快速上手(由于我不太想将太多的精力花在这上面,而ef各方法的资料仍是很全的);二、性能只要过得去就行(又不是要开发对性能要求很苛刻的产品,我想微软的产品也不至于性能很低吧);三、后面若是要换数据库,最好不要改代码(这点是我喜欢ef的主要缘由,只要将数据链接换一下,dll包换一下,数据库就能够从mysql,sqlserver,oracle任意切换)html

 为何用code first?

  一、代码简洁mysql

    相比db first,code first的代码更简洁,基本全部的代码都是真正须要的。而db first有不少自动生成的辅助型的代码。web

  二、编写简单sql

    db first在sqlserver下也简单,但若是是mysql或是oracle,在vs的配置上就会遇到不少问题,我初学时常常遇到vs连mysql失败,或是链接成功后老是生成代码时失败。而用code first,你只要写实体的代码就行,虽然是”多写了一些代码“,但其实速度上比db first仍是快的。数据库

参考资料

  推荐:http://www.entityframeworktutorial.net/code-first/entity-framework-code-first.aspxjson

  微软官方:https://msdn.microsoft.com/en-us/library/aa937723(v=vs.113).aspxapi

 

下面介绍如何实用数组

用法和步骤

引用相关包oracle

  若是是sqlserver数据库,只要引用entityframework就行app

  若是是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,否则一个实体的重命名会致使数据库表的数据丢失,切记切记。

相关文章
相关标签/搜索