快速記一下,已經先有資料庫,又想使用 Code First 模型的解決方案...
並不是每個案子都是從無到有的 green field 專案;已經先有資料庫,卻想要使用 Entity Framework 的 Code First 模型,這種情況肯定會有的。這裡簡略記一下試過的解決方案。
工具:Visual Studio 2012 Update 1 + Entity Framework 5 或 Entity Framework 6 Alpha 2
EF Power Tools
MSDN 網站上有一篇文章:Code First to an Existing Database,裡面用的工具是 EF Power Tools。我嘗試用它對資料庫做逆向工程來以產生 POCO 類別,結果並不順利...
首先碰到的錯誤是:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.DbContextPackage.Extensions.ProjectExtensions.InstallPackage(Project project, String packageId)
at Microsoft.DbContextPackage.Handlers.ReverseEngineerCodeFirstHandler.ReverseEngineerCodeFirst(Project project)
One or more errors occurred while processing template 'Entity.tt'.
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes\EF.Utility.CS.ttinclude(1,4) : error : A processor named 'T4VSHost' could not be found for the directive named 'CleanupBehavior'. The transformation will not be run. The following Exception was thrown:
System.InvalidOperationException: Cannot find processor for directive 'T4VSHost'.
at Microsoft.DbContextPackage.Utilities.EfTextTemplateHost.Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost.ResolveDirectiveProcessor(String processorName)
at Microsoft.VisualStudio.TextTemplating.Engine.ProcessCustomDirectives(ITextTemplatingEngineHost host, TemplateProcessingSession session, IEnumerable`1 directivesToBeProcessed)
臨時解法在這裡可以找到:
http://connect.microsoft.com/VisualStudio/feedback/details/769934/entityframework-bug-in-vs2012-update-1-ctp
此問題解決後,Reverse Engineer Code First 功能已經可以順利執行。接著編譯專案,又會發現另一個問題:好多編譯錯誤。主要是這個:
Compiling transformation: The type or namespace name 'EfTextTemplateHost' could not be found (are you missing a using directive or an assembly reference?)
官方網站有篇文章有提供臨時解法:http://msdn.microsoft.com/en-us/data/jj593170.aspx。然而,也許是忙中有錯,我試了之後仍有同樣的編譯錯誤,問題沒有解決。後來在一個練習用的 Entity Framework 6 Alpha 2 專案中測試,結果也是出現編譯錯誤。
以上問題似乎是在 Visual Studio 2012 Update 1 才會碰到,先前的版本也許會順一點。但無論如何,上述兩個臨時解的步驟都太多了,對於有時間練功研究的人來說不妨一試,但如果是實際的專案開發,還是趁早放棄另尋它法為妙。
EF Reverse POCO Code First Generator
另外試了另一個逆向工程工具:EntityFramework Reverse POCO Code First Generator。初步測試還蠻順的,使用方法也相當簡單。
我也在 EF 6 Alpha 2 的練習專案上簡單測試了一下,可以順利產生 Northwind 範例資料庫的 POCO,而且是將全部的 POCO 類別產生在一個 .cs 檔案中。我將此工具產生出來的 POCO 檔案部分內容貼在這裡:
然後寫點小程式測試一下,也沒問題:
不過,實務上恐怕多少會碰到一些狀況。目前沒有太多時間細究,改天若有進一步測試再補上來。
(有好心人要分享一下嗎其他解決方案嗎?)
並不是每個案子都是從無到有的 green field 專案;已經先有資料庫,卻想要使用 Entity Framework 的 Code First 模型,這種情況肯定會有的。這裡簡略記一下試過的解決方案。
工具:Visual Studio 2012 Update 1 + Entity Framework 5 或 Entity Framework 6 Alpha 2
EF Power Tools
MSDN 網站上有一篇文章:Code First to an Existing Database,裡面用的工具是 EF Power Tools。我嘗試用它對資料庫做逆向工程來以產生 POCO 類別,結果並不順利...
首先碰到的錯誤是:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.DbContextPackage.Extensions.ProjectExtensions.InstallPackage(Project project, String packageId)
at Microsoft.DbContextPackage.Handlers.ReverseEngineerCodeFirstHandler.ReverseEngineerCodeFirst(Project project)
One or more errors occurred while processing template 'Entity.tt'.
C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\Templates\Includes\EF.Utility.CS.ttinclude(1,4) : error : A processor named 'T4VSHost' could not be found for the directive named 'CleanupBehavior'. The transformation will not be run. The following Exception was thrown:
System.InvalidOperationException: Cannot find processor for directive 'T4VSHost'.
at Microsoft.DbContextPackage.Utilities.EfTextTemplateHost.Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost.ResolveDirectiveProcessor(String processorName)
at Microsoft.VisualStudio.TextTemplating.Engine.ProcessCustomDirectives(ITextTemplatingEngineHost host, TemplateProcessingSession session, IEnumerable`1 directivesToBeProcessed)
臨時解法在這裡可以找到:
http://connect.microsoft.com/VisualStudio/feedback/details/769934/entityframework-bug-in-vs2012-update-1-ctp
此問題解決後,Reverse Engineer Code First 功能已經可以順利執行。接著編譯專案,又會發現另一個問題:好多編譯錯誤。主要是這個:
Compiling transformation: The type or namespace name 'EfTextTemplateHost' could not be found (are you missing a using directive or an assembly reference?)
官方網站有篇文章有提供臨時解法:http://msdn.microsoft.com/en-us/data/jj593170.aspx。然而,也許是忙中有錯,我試了之後仍有同樣的編譯錯誤,問題沒有解決。後來在一個練習用的 Entity Framework 6 Alpha 2 專案中測試,結果也是出現編譯錯誤。
以上問題似乎是在 Visual Studio 2012 Update 1 才會碰到,先前的版本也許會順一點。但無論如何,上述兩個臨時解的步驟都太多了,對於有時間練功研究的人來說不妨一試,但如果是實際的專案開發,還是
EF Reverse POCO Code First Generator
另外試了另一個逆向工程工具:EntityFramework Reverse POCO Code First Generator。初步測試還蠻順的,使用方法也相當簡單。
我也在 EF 6 Alpha 2 的練習專案上簡單測試了一下,可以順利產生 Northwind 範例資料庫的 POCO,而且是將全部的 POCO 類別產生在一個 .cs 檔案中。我將此工具產生出來的 POCO 檔案部分內容貼在這裡:
// This file was automatically generated. // Do not make changes directly to this file - edit the template instead. // // The following connection settings were used to generate this file // // Connection String Name: "Northwind" // Connection String: "server=localhost;database=Northwind;Integrated Security=true; Application Name=Test" using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; using System.Data.Entity.ModelConfiguration; namespace EF6CodeFirstExistDatabase { // ************************************************************************ // Database context public class NorthwindEntities : DbContext { public IDbSet<OrderDetails> OrderDetails { get; set; } // Order Details public IDbSet<Orders> Orders { get; set; } // Orders static NorthwindEntities() { Database.SetInitializer<NorthwindEntities>(null); } public NorthwindEntities() : base("Name=Northwind") { } public NorthwindEntities(string connectionString) : base(connectionString) { } protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Configurations.Add(new CustomersConfiguration()); modelBuilder.Configurations.Add(new EmployeesConfiguration()); )); modelBuilder.Configurations.Add(new OrderDetailsConfiguration()); modelBuilder.Configurations.Add(new OrdersConfiguration()); } } // ************************************************************************ // POCO classes // Order Details public class OrderDetails { public int OrderId { get; set; } // OrderID (Primary key) public int ProductId { get; set; } // ProductID (Primary key) public decimal UnitPrice { get; set; } // UnitPrice public short Quantity { get; set; } // Quantity public float Discount { get; set; } // Discount // Foreign keys public virtual Orders Orders { get; set; } // OrderId - FK_Order_Details_Orders public virtual Products Products { get; set; } // ProductId - FK_Order_Details_Products public OrderDetails() { UnitPrice = 0m; Quantity = 1; Discount = 0; } } // Orders public class Orders { public int OrderId { get; set; } // OrderID (Primary key) public string CustomerId { get; set; } // CustomerID public int? EmployeeId { get; set; } // EmployeeID public DateTime? OrderDate { get; set; } // OrderDate public DateTime? RequiredDate { get; set; } // RequiredDate public DateTime? ShippedDate { get; set; } // ShippedDate // ...省略部分屬性... // Reverse navigation public virtual ICollection<OrderDetails> OrderDetails { get; set; } // Order Details.FK_Order_Details_Orders; // Foreign keys public virtual Customers Customers { get; set; } // CustomerId - FK_Orders_Customers public virtual Employees Employees { get; set; } // EmployeeId - FK_Orders_Employees public virtual Shippers Shippers { get; set; } // ShipVia - FK_Orders_Shippers public Orders() { Freight = 0m; OrderDetails = new List<OrderDetails>(); } } // ************************************************************************ // POCO Configuration // Order Details public class OrderDetailsConfiguration : EntityTypeConfiguration<OrderDetails> { public OrderDetailsConfiguration() { ToTable("dbo.Order Details"); HasKey(x => new { x.OrderId, x.ProductId }); Property(x => x.OrderId).HasColumnName("OrderID").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); Property(x => x.ProductId).HasColumnName("ProductID").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.None); Property(x => x.UnitPrice).HasColumnName("UnitPrice").IsRequired(); Property(x => x.Quantity).HasColumnName("Quantity").IsRequired(); Property(x => x.Discount).HasColumnName("Discount").IsRequired(); // Foreign keys HasRequired(a => a.Orders).WithMany(b => b.OrderDetails).HasForeignKey(c => c.OrderId); // FK_Order_Details_Orders HasRequired(a => a.Products).WithMany(b => b.OrderDetails).HasForeignKey(c => c.ProductId); // FK_Order_Details_Products } } // Orders public class OrdersConfiguration : EntityTypeConfiguration<Orders> { public OrdersConfiguration() { ToTable("dbo.Orders"); HasKey(x => x.OrderId); Property(x => x.OrderId).HasColumnName("OrderID").IsRequired().HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); Property(x => x.CustomerId).HasColumnName("CustomerID").IsOptional().HasMaxLength(5); Property(x => x.EmployeeId).HasColumnName("EmployeeID").IsOptional(); Property(x => x.OrderDate).HasColumnName("OrderDate").IsOptional(); // Foreign keys HasOptional(a => a.Customers).WithMany(b => b.Orders).HasForeignKey(c => c.CustomerId); // FK_Orders_Customers HasOptional(a => a.Employees).WithMany(b => b.Orders).HasForeignKey(c => c.EmployeeId); // FK_Orders_Employees HasOptional(a => a.Shippers).WithMany(b => b.Orders).HasForeignKey(c => c.ShipVia); // FK_Orders_Shippers } } }
然後寫點小程式測試一下,也沒問題:
static void Main(string[] args) { using (var db = new NorthwindEntities()) { var customers = from t in db.Customers select t; foreach (var c in customers.Take(5)) { Console.WriteLine(c.CompanyName); } } }
不過,實務上恐怕多少會碰到一些狀況。目前沒有太多時間細究,改天若有進一步測試再補上來。
(有好心人要分享一下嗎其他解決方案嗎?)
沒有留言: