關於EntityFramework 7 開發學習

Entity Framework (又稱ADO.NET Entity Framework) 是微軟以 ADO.NET 爲基礎所發展出來的對象關係對應 (O/R Mapping) 解決方案,早期被稱爲 ObjectSpace,現已經包含在 Visual Studio 2008 Service Pack 1 以及 .NET Framework 3.5 Service Pack 1 中發表。

ADO.NET Entity Framework 以 Entity Data Model (EDM) 爲主,將數據邏輯層切分爲三塊,分別爲 Conceptual Schema, Mapping Schema 與 Storage Schema 三層,其上還有 Entity Client,Object Context 以及 LINQ 可以使用。

下面說下我用 EF7 開發項目的一些筆記(原創文章:詳見我要源碼網):

暫時開發模式

說明:The EF7 NuGet packages use some new metadata that is only supported in NuGet 2.8.3 or higher.

EF7 目前只能通過 NuGet 進行管理,所以,首先確定你的 Visual Studio 中的 NuGet 爲最新版本(最低支持 2.8.3,最新版本 3.0)。

然後需要在 Tools –> NuGet Package Manager –> Package Manager Settings 中配置 Package Sources:https://www.myget.org/F/aspnetvnext/api/v2/,VS 2015 不需要進行添加。

我使用的是 VS 2015 開發的,所以 NuGet 不需要任何配置,使用 EF 之前,需要添加一個類庫項目。

這是 VS 2015 中 ASP.NET 5 的三種模版,首先需要明確的是,ASP.NET 5 Class Library 項目可以在其他兩個項目之前進行引用,但不能被其他非 ASP.NET 5 項目引用,相反,ASP.NET 5 項目也不能引用其他類型的類庫項目,如果強行引用,就會抱下面錯誤:

所以說,如果你的 Web 項目爲 ASP.NET 5,那你開發的所有類庫項目必須爲 ASP.NET 5 Class Library 類型的。

Code First 具體體現

創建 ASP.NET 5 Class Library 類型的 EF7 項目,像平常 EF 開發一樣,我們需要在 EF7 項目中添加項,但你會發現,選擇項模版中並沒有“ADO.NET Entity Date Model”項。

EF6:

EF7:

“ADO.NET Entity Date Model”,就是“Code First Only”的具體表現,沒辦法,EF7 逼着你自行寫實體代碼。

DbContext 配置

EF7DbContext 示例代碼:

using Microsoft.Data.Entity; using Microsoft.Data.Entity.Metadata; using System;

namespace EF7
{ public class EF7DbContext : DbContext
    { public DbSet<Entity> Entities { get; set; } protected override void OnConfiguring(DbContextOptions builder)
        {
            builder.UseSqlServer(@"data source=.;initial catalog=EF7Db;integrated security=True;");
        } protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Entity>()
               .ForRelational()
               .Table("Entities");
            modelBuilder.Entity<Entity>()
                .Key(n => n.Id);
            modelBuilder.Entity<Entity>()
                .Property(t => t.Id)
                .GenerateValuesOnAdd(false); base.OnModelCreating(modelBuilder);
        }
    }
}

OnModelCreating 方法沒有變化,變化的是內部實現,映射配置後面講下,OnConfiguring 是新加入的,builder.UseSqlServer 的作用就是綁定連接字符串,相當於之前版本 App.config 中的 connectionStrings,這個配置也可以在 ASP.NET 5 Web 的 Startup.cs 中進行配置,如下:

public class Startup
{ public Startup(IHostingEnvironment env)
    { // Setup configuration sources. Configuration = new Configuration()
            .AddJsonFile("config.json")
            .AddEnvironmentVariables();
    } public IConfiguration Configuration { get; set; } // This method gets called by the runtime. public void ConfigureServices(IServiceCollection services)
    { // Add EF services to the services container. services.AddEntityFramework()
            .AddSqlServer()
            .AddDbContext<CNBlogsNewsDbContext>(); //.AddDbContext<CNBlogsNewsDbContext>(options => //{ //    //options.UseSqlServer(Configuration.Get("Data:DefaultConnection:ConnectionString")); //    options.UseSqlServer(); //}); // Add MVC services to the services container. services.AddMvc(); // Uncomment the following line to add Web API servcies which makes it easier to port Web API 2 controllers. // You need to add Microsoft.AspNet.Mvc.WebApiCompatShim package to project.json // services.AddWebApiConventions(); }
}

AddEntityFramework 的配置模式有很多,比如上面配置中就不使用 EF7DbContext 中的連接字符串,而是讀取 config.json 配置文件中的 ConnectionString,詳細內容在 ASP.NET 5 記錄中再進行說明,在 EF7DbContext 的示例代碼中,我們會發現沒有了 EF7DbContext 構造函數,之前都是在構造函數中寫一大堆東西,比如:

public EF6DbContext()
    : base("name=EF6Db")
{ this.Configuration.LazyLoadingEnabled = false;
    Database.SetInitializer<EF6DbContext>(null);
}

這部分配置都移到 EF7DbContext 中的 OnConfiguring(DbContextOptions) 進行配置。

更多內容,請參考:Configuring a DbContext

Entity 映射關聯配置

示例代碼:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Entity>()
        .ForRelational()
        .Table("Entities");
    modelBuilder.Entity<Entity>()
        .Key(n => n.Id);
    modelBuilder.Entity<Entity>()
        .Property(t => t.Id)
        .GenerateValuesOnAdd(false);
    modelBuilder.Entity<ChildEntity>()
        .Key(n => n.Id);
    modelBuilder.Entity<ChildEntity>()
        .ManyToOne(n => n.Entity, t => t.ChildEntities)
        .ForeignKey(t => t.EntityId);
    base.OnModelCreating(modelBuilder);
}

對 Entity 屬性的一些配置,我們也可以在屬性的上面進行配置(比如 Key、Required、DataType 等),命令空間:System.ComponentModel.DataAnnotations,Table 配置是我無意間發現的,我原以爲 EF7 不能對 Entity 進行表的重命名,之前我記得在 EF6 中是有 ToTable() 方法的,或者在 Entity 上面進行 Table() 屬性配置,但在 EF7中改爲了 ForRelational,所在程序集爲:EntityFramework.Relational,GenerateValuesOnAdd 的配置說明是否爲 identity,之前 EF 版本配置爲:HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity),Entity 之間的關聯配置:

IT經典笑語錄:delphi就象吉普車,什麼路上都能開,卻什麼路上也開不好,pb就像是卡丁車,只能在固定線路上開,到了室外 就有些不穩了,vc就象是跑車,你開的起卻買不起,而且一旦發生故障,想修都找不到毛病在哪,java就像敞棚車,不管颳風下雨,還是豔陽高照,都能照開不誤,vb就是摩托車了,騎的時間越長,你越痛恨它!

  • OneToOne:一對一
  • OneToMany:一對多
  • ManyToOne:多對一

EF7 Entity 之間的關聯配置更加簡單明瞭,EF 之前版本配置(HasRequired 或 HasRequired):

HasOptional(x => x.ParentMessage)
    .WithMany()
    .Map(x => x.MapKey("ParentID")) //.HasForeignKey(c => c.ParentID) .WillCascadeOnDelete(false);

Migration 問題紀錄

參考:Using EF7 in Traditional .NET Applications

這是 EF7 的官方使用說明,其中有提到 Migration(遷移)的部分用法,其實很簡單,總共就四步:

  1. Install-Package EntityFramework.SqlServer –Pre
  2. Install-Package EntityFramework.Commands -Pre
  3. Add-Migration MyFirstMigration
  4. Apply-Migration

EF7DbContext 並不需要任何配置,但試過之後會發現,一大堆的問題,而且解決方案也搜不到,已經困擾一兩天的時間了,下面紀錄下過程。

之前寫過一篇 EF Code First 的博文,裏面有提到 EF 代碼遷移的使用方法(非 EF7 版本),大致爲:

  1. Enable-Migrations
  2. Add-Migration Update-NewType-Name
  3. Update-Database

EF 7 代碼遷移命令的完整說明(來自 get-help {命令名稱} -full):

  1. Use-DbContext [-Context] [[-Project] ] []
  2. Add-Migration [-Name] [[-Context] ] [[-Project] ] []
  3. Apply-Migration [[-Migration] ] [[-Context] ] [[-Project] ] []
  4. Update-Database [[-Migration] ] [[-Context] ] [[-Project] ] []
  5. Script-Migration [[-From] ] [[-To] ] [[-Context] ] [[-Project] ] [-Idempotent] []

首先,按照EF7 Wiki 說明,在 Package Manager Console 中輸入:Add-Migration MyFirstMigration 命令,會報如下錯誤:

異常完整信息:Add-Migration : The term 'Add-Migration' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was in.

什麼意思呢?直接說就是找不到“Add-Migration”命令,EF7 Migration 的所有命令管理都在 EntityFramework.Commands 程序集,所以我們使用 Migration 之前,都必須 NuGet 安裝一下,找不到“Add-Migration”命令,這個問題困擾我很久,也沒有找到相關資料,因爲 Migration 的命令方式都是 PowerShell,我對這東西一竅不通,沒辦法,後來我嘗試不使用 EF7,而是使用 EF6 進行 Migration 配置,發現是可以的,這就很奇怪,回過頭再用 EF7 輸入命令“Add-Migration”,就會報另一種錯誤:

異常完整信息:Join-Path : Cannot bind argument to parameter 'Path' because it is null.At C:\Users\yuezhongxin\Desktop\ConsoleApp1\packages\EntityFramework.6.1.1\tools\EntityFramework.psm1:713 char:28

什麼意思?就是因爲“Path”參數問題,不能加載“Add-Migration”命令,和上面異常不同的是,這個異常給出錯誤地址了:“EntityFramework.6.1.1\tools\EntityFramework.psm1”,但有個問題是,我使用的是 EF7,爲什麼會報 EntityFramework.6.1.1 的異常,這個問題也困擾我很久,最後在一篇博文中找到答案及解決方式:Entity Framework 5.0系列之Code First數據庫遷移,大致意思是說 Migration 命令沒有加載最新版本的 EntityFramework,所以需要在 Package Manager Console 中手動配置一下:

  1. Import-Module C:\Users\yuezhongxin.kpm\packages\EntityFramework.Commands\7.0.0-beta1\tools\EntityFramework.psd1
  2. Install-Package EntityFramework.Commands -IncludePrerelease

在 EF 之前版本中 EntityFramework.psd1 文件位置都會在 EntityFramework 程序集文件中,但在 EF7 中,被分離在了 EntityFramework.Commands 程序集文件中了,第二步的作用是重新加載程序集。

異常完整信息:The names of some imported commands from the module 'EntityFramework' include unapproved verbs that might make them less discoverable. To find the commands with unapproved verbs, run the Import-Module command again with the Verbose parameter. For a list of approved verbs, type Get-Verb.

Import-Module EF6 是成功的,但 Import-Module EF7 就會出現上面的警告信息,具體原因不得而知,在 Package Manager Console 中輸入“Add-Migration MyFirstMigration”命令,會出現下面異常:

異常完整信息:Add-Migration : Cannot bind argument to parameter 'Path' because it is null.At line:1 char:1

但輸入“get-help Add-Migration -full”命令(查看 Add-Migration 幫助信息),就會發現 Add-Migration 命令並沒有任何問題,也就是說 EntityFramework.Commands 是可以使用的:

其實問題出現的原因無非就是兩點:

  1. EntityFramework.Commands 中的 Migration 命令
  2. EF7DbContext 配置

網上關於 EF7 Migration 的資料實在少得可憐,這個問題我也只探究到這一步,畢竟還要做事,就紀錄到這,等待後續解決!

珍貴的參考資料:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章