中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Entity?Framework如何使用Code?First模式管理數據庫

發布時間:2022-03-05 14:05:06 來源:億速云 閱讀:159 作者:小新 欄目:開發技術

這篇文章主要為大家展示了“Entity Framework如何使用Code First模式管理數據庫”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“Entity Framework如何使用Code First模式管理數據庫”這篇文章吧。

一、管理數據庫連接

1、使用配置文件管理連接之約定

在數據庫上下文類中,如果我們只繼承了無參數的DbContext,并且在配置文件中創建了和數據庫上下文類同名的連接字符串,那么EF會使用該連接字符串自動計算出數據庫的位置和數據庫名。比如,我們的數據庫上下文定義如下:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConventionConfigure.EF
{
    /// <summary>
    /// 繼承無參數的DbContext
    /// </summary>
    public class SampleDbEntities :DbContext
    {
        public SampleDbEntities()
        {
            // 數據庫不存在時創建數據庫
            Database.CreateIfNotExists();
        }
    }
}

在配置文件中定義的連接字符串如下:

<connectionStrings>
    <add name="SampleDbEntities" connectionString="Data Source=.;Initial Catalog=TestDb;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>

定義的連接字符串中name的value值和創建的數據庫上下文類的類名相同,這樣EF會使用該連接字符串執行數據庫操作,究竟會發生什么呢?

運行程序,Program類定義如下:

using ConventionConfigure.EF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConventionConfigure
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new SampleDbEntities())
            { }

            Console.WriteLine("創建成功");
            Console.ReadKey();
        }
    }
}

當運行應用程序時,EF會尋找我們的數據庫上下文類,即“SampleDbEntities”,并在配置文件中尋找和它同名的連接字符串,然后它會使用該連接字符串計算出應該使用哪個數據庫provider,之后檢查數據庫位置,之后會在指定的位置創建一個名為TestDb.mdf的數據庫文件,同時根據連接字符串的Initial Catalog屬性創建了一個名為TestDb的數據庫。創建的數據庫結構如下:

Entity?Framework如何使用Code?First模式管理數據庫

查看創建后的數據庫,會發現只有一張遷移記錄表。

2、使用已經存在的ConnectionString

如果我們已經有了一個定義數據庫位置和名稱的ConnectionString,并且我們想在數據庫上下文類中使用這個連接字符串,連接字符串如下:

<connectionStrings>
    <add name="AppConnection" connectionString="Data Source=.;Initial Catalog=TestDb;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
</connectionStrings>

以上面創建的數據庫TestDb作為已經存在的數據庫,新添加實體類Student,使用已經存在的ConnectionString查詢數據庫的Student表,Student實體類定義如下:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExistsConnectionString.Model
{
    [Table("Student")]
    public class Student
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public string Sex { get; set; }

        public int Age { get; set; }
    }
}

我們將該連接字符串的名字傳入數據庫上下文DbContext的有參構造函數中,數據庫上下文類定義如下:

using ExistsConnectionString.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExistsConnectionString.EF
{
    public class SampleDbEntities : DbContext
    {
        public SampleDbEntities()
            : base("name=AppConnection")
        {

        }

        // 添加到數據上下文中
        public virtual DbSet<Student> Students { get; set; }
    }
}

上面的代碼將連接字符串的名字傳給了DbContext類的有參構造函數,這樣一來,我們的數據庫上下文就會開始使用該連接字符串了,在Program類中輸出Name和Age字段的值:

using ExistsConnectionString.EF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExistsConnectionString
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new SampleDbEntities())
            {
                foreach (var item in context.Students)
                {
                    Console.WriteLine("姓名:"+item.Name+" "+"年齡:"+item.Age);
                }
            }
        }
    }
}

運行程序,發現會報下面的錯誤:

Entity?Framework如何使用Code?First模式管理數據庫

出現上面報錯的原因是因為數據庫上下文發生了改變,與現有數據庫不匹配。解決方案:

把數據庫里面的遷移記錄表刪掉或者重命名即可。

重新運行程序,結果如下:

Entity?Framework如何使用Code?First模式管理數據庫

注意:如果在配置文件中還有一個和數據庫上下文類名同名的ConnectionString,那么就會使用這個同名的連接字符串。無論我們對傳入的連接字符串名稱如何改變,都是無濟于事的,也就是說和數據庫上下文類名同名的連接字符串優先權更大。(即約定大于配置)

3、使用已經存在的連接

通常在一些老項目中,我們只會在項目中的某個部分使用EF Code First,同時,我們想對數據上下文類使用已經存在的數據庫連接,如果要實現這個,可將連接對象傳給DbContext類的構造函數,數據上下文定義如下:

using ExistsDbConnection.Model;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ExistsDbConnection.EF
{
    public class SampleDbEntities :DbContext
    {
        public SampleDbEntities(DbConnection con)
            : base(con, contextOwnsConnection: false)
        {

        }

        public virtual DbSet<Student> Students { get; set; }
    }
}

這里要注意一下contextOwnsConnection參數,之所以將它作為false傳入到上下文,是因為它是從外部傳入的,當上下文超出了范圍時,可能會有人想要使用該連接。如果傳入true的話,那么一旦上下文出了范圍,數據庫連接就會立即關閉。

Program類定義如下:

using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
using ExistsDbConnection.EF;

namespace ExistsDbConnection
{
    class Program
    {
        static void Main(string[] args)
        {
            // 讀取連接字符串
            string conn = ConfigurationManager.ConnectionStrings["AppConnection"].ConnectionString;
            // DbConnection是抽象類,不能直接實例化,聲明子類指向父類對象
            DbConnection con = new SqlConnection(conn);
            using (var context = new SampleDbEntities(con))
            {
                foreach (var item in context.Students)
                {
                    Console.WriteLine("姓名:" + item.Name + " " + "年齡:" + item.Age);
                }
            }

            Console.WriteLine("讀取完成");
            Console.ReadKey();
        }
    }
}

運行程序,結果如下:

Entity?Framework如何使用Code?First模式管理數據庫

二、管理數據庫創建

首次運行EF Code First應用時,EF會做下面的這些事情:
1、檢查正在使用的DbContext類。
2、找到該上下文類使用的connectionString。
3、找到領域實體并提取模式相關的信息。
4、創建數據庫。
5、將數據插入系統。

一旦模式信息提取出來,EF會使用數據庫初始化器將該模式信息推送給數據庫。數據庫初始化器有很多可能的策略,EF默認的策略是如果數據庫不存在,那么就重新創建;如果存在的話就使用當前存在的數據庫。當然,我們有時也可能需要覆蓋默認的策略,可能用到的數據庫初始化策略如下:

CreateDatabaseIfNotExists:CreateDatabaseIfNotExists:顧名思義,如果數據庫不存在,那么就重新創建,否則就使用現有的數據庫。如果從領域模型中提取到的模式信息和實際的數據庫模式不匹配,那么就會拋出異常。

DropCreateDatabaseAlways:如果使用了該策略,那么每次運行程序時,數據庫都會被銷毀。這在開發周期的早期階段通常很有用(比如設計領域實體時),從單元測試的角度也很有用。

DropCreateDatabaseIfModelChanges:這個策略的意思就是說,如果領域模型發生了變化(具體而言,從領域實體提取出來的模式信息和實際的數據庫模式信息失配時),就會銷毀以前的數據庫(如果存在的話),并創建新的數據庫。

MigrateDatabaseToLatestVersion:如果使用了該初始化器,那么無論什么時候更新實體模型,EF都會自動地更新數據庫模式。這里很重要的一點是:這種策略更新數據庫模式不會丟失數據,或者是在已有的數據庫中更新已存在的數據庫對象。MigrateDatabaseToLatestVersion初始化器只有從EF4.3才可用。

1、設置初始化策略

EF默認使用CreateDatabaseIfNotExists作為默認初始化器,如果要覆蓋這個策略,那么需要在DbContext類中的構造函數中使用Database.SetInitializer方法,下面的例子使用DropCreateDatabaseIfModelChanges策略覆蓋默認的策略。數據庫上下文類定義如下:

using InitializationStrategy.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationStrategy.EF
{
    public class SampleDbEntities : DbContext
    {
        public SampleDbEntities()
            : base("name=AppConnection")
        {
            // 使用DropCreateDatabaseIfModelChanges策略覆蓋默認的策略
            Database.SetInitializer<SampleDbEntities>(new DropCreateDatabaseIfModelChanges<SampleDbEntities>());
        }

        // 添加到數據上下文中
        public virtual DbSet<Student> Students { get; set; }
    }
}

這樣一來,無論什么時候創建上下文類,Database.SetInitializer()方法都會被調用,并且將數據庫初始化策略設置為DropCreateDatabaseIfModelChanges。

Student領域實體類新增加Email和Address兩個屬性:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationStrategy.Model
{
    [Table("Student")]
    public class Student
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public string Sex { get; set; }

        public int Age { get; set; }

        public string Email { get; set; }

        public string Address { get; set; }
    }
}

Program類定義如下:

using InitializationStrategy.EF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationStrategy
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new SampleDbEntities())
            {
                foreach (var item in context.Students)
                {

                }
            }

            Console.WriteLine("創建成功");
            Console.ReadKey();
        }
    }
}

運行程序后,數據庫表結構如下:

Entity?Framework如何使用Code?First模式管理數據庫

注意:如果處于生產環境,那么我們肯定不想丟失已經存在的數據。這時我們就需要關閉該初始化器,只需要將null傳給Database.SetInitlalizer()方法,如下所示:

public SampleDbEntities(): base("name=AppConnection")
{
Database.SetInitializer<SampleDbEntities>(null);
}

2、填充種子數據

到目前為止,無論我們選擇哪種策略初始化數據庫,生成的數據庫都是一個空的數據庫。但是許多情況下我們總想在數據庫創建之后、首次使用之前就插入一些數據。此外,開發階段可能想以admin的資格為其填充一些數據,或者為了測試應用在特定的場景中表現如何,想要偽造一些數據。

當我們使用DropCreateDatabaseAlways和DropCreateDatabaseIfModelChanges初始化策略時,插入種子數據非常重要,因為每次運行應用時,數據庫都要重新創建,每次數據庫創建之后在手動插入數據非常乏味。接下來我們看一下當數據庫創建之后如何使用EF來插入種子數據。

為了向數據庫插入一些初始化數據,我們需要創建滿足下列條件的數據庫初始化器類:

1、從已存在的數據庫初始化器類中派生數據。
2、在數據庫創建期間種子化。

下面演示如何初始化種子數據

1、定義領域實體類
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationSeed.Model
{
    [Table("Employee")]
    public class Employee
    {
        public int EmployeeId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

    }
}
2、創建數據庫上下文

使用EF的Code First方式對上面的模型創建數據庫上下文:

public class SampleDbEntities : DbContext
{
    public virtual DbSet<Employee> Employees { get; set; }
}

3、創建數據庫初始化器類

假設我們使用的是DropCreateDatabaseAlways數據庫初始化策略,那么初始化器類就要從該泛型類繼承,并傳入數據庫上下文作為類型參數。接下來,要種子化數據庫就要重寫DropCreateDatabaseAlways類的Seed()方法,而Seed()方法拿到了數據庫上下文,因此我們可以使用它來將數據插入數據庫:

using InitializationSeed.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationSeed.EF
{

    /// <summary>
    /// 數據庫初始化器類
    /// </summary>
    public class SeedingDataInitializer : DropCreateDatabaseAlways<SampleDbEntities>
    {
        /// <summary>
        /// 重寫DropCreateDatabaseAlways的Seed方法
        /// </summary>
        /// <param name="context"></param>
        protected override void Seed(SampleDbEntities context)
        {
            for (int i = 0; i < 6; i++)
            {
                var employee = new Employee
                {
                  FirstName="測試"+(i+1),
                  LastName="工程師"
                };

                context.Employees.Add(employee);

            }
                base.Seed(context);
        }
    }
}

上面的代碼通過for循環創建了6個Employee對象,并將它們添加給數據庫上下文類的Employees集合屬性。這里值得注意的是我們并沒有調用DbContext.SaveChanges()方法,因為它會在基類中自動調用。

4、將數據庫初始化器類用于數據庫上下問類

using InitializationSeed.Model;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationSeed.EF
{
    public class SampleDbEntities :DbContext
    {
        public SampleDbEntities()
            : base("name=AppConnection")
        {
            // 類型傳SeedingDataInitializer
            Database.SetInitializer<SampleDbEntities>(new SeedingDataInitializer());
        }

        // 領域實體添加到數據上下文中
        public virtual DbSet<Employee> Employees { get; set; }
    }
}

5、Main方法中訪問數據庫

using InitializationSeed.EF;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace InitializationSeed
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var context = new SampleDbEntities())
            {
                foreach (var item in context.Employees)
                {
                    Console.WriteLine("FirstName:"+item.FirstName+" "+"LastName:"+item.LastName);
                }
            }

            Console.WriteLine("讀取完成");
            Console.ReadKey();
        }
    }
}

6、運行程序,查看結果

Entity?Framework如何使用Code?First模式管理數據庫

查看數據庫

Entity?Framework如何使用Code?First模式管理數據庫

種子數據填充完成。

7、使用數據遷移的方式填充種子數據

使用數據遷移的方式會生成Configuration類,Configuration類定義如下:

namespace DataMigration.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<DataMigration.SampleDbEntities>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(DataMigration.SampleDbEntities 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.
        }
    }
}

重寫Configuration類的Seed()方法也可以實現插入種子數據,重寫Seed()方法:

namespace DataMigration.Migrations
{
    using DataMigration.Model;
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<DataMigration.SampleDbEntities>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(DataMigration.SampleDbEntities 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.

            context.Employees.AddOrUpdate(
                 new Employee { FirstName = "測試1", LastName = "工程師" },
                 new Employee { FirstName = "測試2", LastName = "工程師" }

                );
        }
    }
}

使用數據遷移,然后查看數據庫結果:

Entity?Framework如何使用Code?First模式管理數據庫

發現使用數據遷移的方式也將種子數據插入到了數據庫中。

以上是“Entity Framework如何使用Code First模式管理數據庫”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

绥德县| 新民市| 东乌珠穆沁旗| 黎川县| 巫山县| 怀集县| 治县。| 黄梅县| 武宁县| 阿合奇县| 和田县| 仲巴县| 龙岩市| 深泽县| 永善县| 土默特右旗| 宝清县| 民乐县| 阿鲁科尔沁旗| 平定县| 常熟市| 永城市| 和硕县| 社会| 石门县| 从江县| 孟连| 景泰县| 克什克腾旗| 商水县| 阜南县| 长春市| 彝良县| 延津县| 永年县| 陇川县| 吉水县| 甘泉县| 东至县| 温泉县| 彰武县|