EntityFrameworkCore v1.1.1 問題彙總(整理的不錯)

隨着宇宙第一IDE的最新版本發佈[2017/3/7],AspNetCore 和EntityFrameworkCore(團隊)都發布了最新的代碼。

不過在我看來,這些到還不是最重要的。最重要的是dotnet cli終於rtm了,以及和它配套的各類工具。好雞凍啊,終於不用管beta,preview,final,final-update之類的版本了。雖然今後一定還會有各類版本發佈,但是本次發佈之後,工具的很多使用方式和習慣都會定下來(一些),方便我們這種用戶使用和記憶。

image

問題環境

爲了跟進新本版,在安裝了vs2017之後,我就迫不及待地搭建了一個項目進行測試。

image

項目

內容

EfCore11.Domain Entity類型,不需要引用其他nuget包
EfCore11.DataSqlServer DbContext項目,需要引用Microsoft.EntityFrameworkCore.SqlServer等nuget包
EfCore11.SomeUI AspnetCore MVC項目,可以通過dotnet new mvc命令生成

其中的項目文件:

Domain項目中的Blog.cs文件

  1 using System.Collections.Generic;
  2 
  3 namespace EfCore11.Domain
  4 {
  5     public class Blog
  6     {
  7         public int Id { get; set; }
  8         public string Name { get; set; }
  9         public string Url { get; set; }
 10         public ICollection<Post> Posts { get; set; }
 11     }
 12 }
 13 

Domain項目中的Post.cs文件

  1 namespace EfCore11.Domain
  2 {
  3     public class Post
  4     {
  5         public int Id { get; set; }
  6         public string Title { get; set; }
  7         public string Body { get; set; }
  8 
  9         public int BlogId { get; set; }
 10         public Blog Blog { get; set; }
 11     }
 12 }
 13 

DataSqlServer項目中的BlogDbContext.cs文件

  1 using EfCore11.Domain;
  2 using Microsoft.EntityFrameworkCore;
  3 
  4 namespace EfCore11.DataSqlServer
  5 {
  6     public class BlogDbContext : DbContext
  7     {
  8         public DbSet<Post> Post { get; set; }
  9         public DbSet<Blog> Blog { get; set; }
 10 
 11         public BlogDbContext(DbContextOptions<BlogDbContext> option)
 12             : base(option)
 13         {
 14 
 15         }
 16     }
 17 }

SomeUI項目中Startup.cs文件中修改的代碼

  1 public void ConfigureServices(IServiceCollection services)
  2 {
  3     // Add framework services.
  4     services.AddMvc();
  5     // 此處不用json配置的方法了,因爲不是本文的重點。如有需要請自行baidu
  6     string conn = "server=(localdb)\\mssqllocaldb;database=Ef.Core;Trusted_connection=true;";
  7     services.AddDbContext<BlogDbContext>(opt => opt.UseSqlServer(conn));
  8 }

問題0:在哪個項目上執行 code first migration 呢?

按照現在的項目機構,可以執行code first migration 的項目有兩個:分別是DbContext項目,也就是本文環境中的DataSqlServer項目;以及Mvc項目,也就是本文中的SomeUI項目。

這兩個項目都可以完成數據庫遷移所需的操作,但是實現目有所不同。因爲在哪個項目內完成遷移就意味着要由哪個項目中維護相應的遷移代碼,而用於生產環境的MVC項目是不會包含全部數據庫遷移代碼的(理由很多了,誰也不會把包含“簡歷生成事件”的代碼放到生產環境上的),所以通常情況下的開發項目採用DbContext項目管理遷移代碼,測試環境隨意。

 

 

先說簡單的,在MVC環境下遷移:

問題1:執行 dotnet ef 命令錯誤

重現方法:CMD打開SomeUI目錄,然後執行“dotnet ef”命令

報錯內容:No executable found matching command "dotnet-ef"

問題解釋:ef core編寫時其內容被拆分成爲了很多包,以方便程序員只加載程序所需的代碼,這樣程序就會佔用更小的內存,運行速度更快,部署更容易。所以想要運行dotnet-ef命令,還需要加載Microsoft.EntityFrameworkCore.Tools.DotNet

此包的描述是這樣的

image

處理方法:因爲目前dotnet cli還沒有直接添加命令行工具引用的方法,所以只能暴力一點兒了,直接修改csproj文件:

在ProjectGroup標籤下直接添加:

  1   <ItemGroup>
  2     <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="1.0.0" />
  3   </ItemGroup>

//添加完畢後,如果你的vs出現了一些奇怪的現象,比如nuget包沒有加載,引用不正常,可以嘗試關閉當前的項目,然後重新打開項目來解決這個問題。

//看上去就是項目文件沒有在修改後重新加載,希望update1的時候能夠更穩定一些。

修復檢查:重新執行dotnet ef,能看到獨角獸啊

image

問題2:執行 dotnet ef migrations add initial 報錯

重現方法:CMD打開SomeUI目錄,執行“dotnet ef migrations add initial”

報錯內容:Could not load file or assembly 'Microsoft.EntityFrameworkCore.Design, Culture=neutral, PublicKeyToken=null'. 緋葷粺鎵句笉鍒版寚瀹氱殑鏂囦歡銆

問題解釋:和上一個問題一樣,而且錯誤信息也說的比較明確,就是還缺少一個nuget包:Microsoft.EntityFrameworkCore.Design

處理方法:在cli下的添加方式是執行:dotnet add package Microsoft.EntityFrameworkCore.Design

修復檢查:再次執行dotnet ef migrations add initial ,報錯信息更改了:

image

問題3:遷移報錯,需要指定包含遷移的程序集

重現方法:詳見問題2

報錯內容:Your target project 'xxxxx' doesn't match your migrations assembly xxxxxxxx'. Either change your target project or change your migrations assembly.

問題解釋:當前執行遷移項目和包含DbContext程序集項目不一致,要麼更改執行遷移操作的項目,要麼修改遷移程序集。

處理方法:兩條路自己選,要麼切換到用DbContext程序集管理遷移代碼,要麼修改當前代碼以適應遷移方法。錯誤信息裏給出了一個簡單的解決方法:

Change your migrations assembly by using DbContextOptionsBuilder. E.g. options.UseSqlServer(connection, b => b.MigrationsAssembly("EfCore11.SomeUI")). By default, the migrations assembly is the assembly containing the DbContext.
Change your target project to the migrations project by using the Package Manager Console's Default project drop-down list, or by executing "dotnet ef" from the directory containing the migrations project.

對應修改的代碼是SomeUI項目的Startup.cs文件

  1 public void ConfigureServices(IServiceCollection services)
  2 {
  3     // Add framework services.
  4     services.AddMvc();
  5     // 此處不用json配置的方法了,因爲不是本文的重點。如有需要請自行baidu
  6     string conn = "server=(localdb)\\mssqllocaldb;database=Ef.Core;Trusted_connection=true;";
  7     services.AddDbContext<BlogDbContext>(opt => opt.UseSqlServer(conn
  8         ,b=>b.MigrationsAssembly("EfCore11.SomeUI")
  9         ));
 10 }

修復檢查:重新執行遷移命令,成功。

image

之後再執行“dotnet ef database update”就可以按照現有代碼遷移,創建相應的數據庫了。

至此,簡單的代碼遷移過程完成了。不過以上流程的解決方案不用劃分爲三個項目也可以實現,如果想要實現複雜項目或者用於部署身纏環境的方案,還需要過以下坑。

 

使用DbContext項目遷移:

對於環境和代碼改動需要回滾到問題0。然後使用CMD打開DataSqlServer目錄。

執行 dotnet ef命令,會遇到問題1,問題2的錯誤,根據描述進行修改即可,不過需要注意項目已經更換,不要改錯地方了  :)

問題4:ef tooling 對於.NetStandard的支持問題

重現方法:CMD執行代碼遷移

報錯內容:Startup project 'EfCore11.DataSqlServer.csproj' targets framework '.NETStandard'. This framework is not intended for execution and may fail to resolve runtime dependencies. If so, specify a different project using the --startup-project option and try again.

image

問題解釋:這不是很嚴重的問題,所以錯誤用黃色顯示。因爲當前版本的EF 命令行工具對於.NetStandard支持有限,所以會出現一個警告信息。如果真的想要修改這個問題,目前只能通過修改csproj文件,將targetFramework修改爲netcoreapp1.1.

 

問題5:無法初始化DbContext

重現方法:CMD執行代碼遷移

報錯內容:No parameterless constructor was found on 'BlogDbContext'. Either add a parameterless constructor to 'BlogDbContext' or add an implementation of 'IDbContextFactory<BlogDbContext>' in the same assembly as 'BlogDbContext'.

問題解釋:因爲文中的DbContext 沒有給出無參構造器,要麼給出無參構造器,要麼實現IDbContextFactory。此處又出現了分支,按慣例,先說簡單的:通過-s|—startup-project參數讓mvc程序注入一個“'IDbContextFactory<BlogDbContext>”,這樣DbContext 就可以正常初始化了。

相對比較複雜的方法需要修改代碼,詳見問題6.

處理方法:CMD執行行命令“dotnet ef migrations add initialCreate -s ..\EfCore11.SomeUI”

修復檢查

image

問題6:實現無參構造器的DbContext參與遷移

重現方法:

   修改代碼:DataSqlServer的BlogDbContext.cs文件

  1 using EfCore11.Domain;
  2 using Microsoft.EntityFrameworkCore;
  3 
  4 namespace EfCore11.DataSqlServer
  5 {
  6     public class BlogDbContext : DbContext
  7     {
  8         public DbSet<Post> Post { get; set; }
  9         public DbSet<Blog> Blog { get; set; }
 10 
 11         //public BlogDbContext(DbContextOptions<BlogDbContext> option)
 12         //    : base(option)
 13         //{
 14 
 15         //}
 16 
 17         // 因爲使用無參構造器,所以需要自帶鏈接字符串
 18         protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
 19         {
 20             optionsBuilder.UseSqlServer("server=(localdb)\\mssqllocaldb;database=Ef.Core;Trusted_connection=true;");
 21         }
 22     }
 23 }

   執行命令:dotnet ef migrations add initialCreate

再執行命令:dotnet ef database update

報錯內容:Could not load file or assembly 'System.Data.SqlClient, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. 緋葷粺鎵句笉鍒版寚瀹氱殑鏂囦歡銆  

        :Could not load file or assembly 'System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

問題解釋:錯誤信息不同是因爲DbContext項目使用了不同的targetFramework,如果是targetFramework=netstandard1.4,則錯誤爲無法加載System.Data.SqlClient,如果按照問題4修改了targetFramework=netcoreapp1.1,則錯誤爲無法加載 System.Diagnostics.DiagnosticSource。

這個問題確實很奇葩,從錯誤信息完全不能弄清到底該怎麼處理。目前ef team給出的解決辦法有點兒繞,又使用了MVC項目。我相信這個解決方法只是一個臨時處理措施,後期EF Team會妥善處理這個問題。

處理方法:CMD執行行命令“dotnet ef database update -s ..\EfCore11.SomeUI”     //walkaround

修復檢查:執行命令時會顯示創建數據庫的sql語句

image

 

問題處理完畢,最終結果是

image

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