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,否則一個實體的重命名會致使數據庫表的數據丟失,切記切記。

相關文章
相關標籤/搜索