在前面的文章中咱們提到Entity Framework的「Code First」模式也一樣能夠基於現有數據庫進行開發。今天就讓咱們一塊兒看一下使用Entity Framework Power Tools如何基於現有數據庫生成數據類和數據庫上下等。數據庫
基於現有數據庫生成POCO數據類和數據庫上下文須要藉助Visual Studio一個擴展插件-- Entity Framework Power Tools(一個Code First反向工程工具)。只要在Visual Studio擴展裏面輸入「Entity Framework Power」搜索便可找到最新的擴展,點擊下載便可(以下圖)。固然你也能夠到這裏Entity Framework Power Tools Beta 3下載安裝包進行安裝。架構
安裝完以後只要在項目上右鍵選擇Entity Framework->Reverse Engineer Code First(項目中首先須要安裝Entity Framework 包,不然會有錯誤),而後在彈出的窗口中輸入相關的數據庫鏈接信息便可(咱們這裏使用「AdventureWorks」數據庫)。app
![]() |
注意:若是使用「AdventureWorks」數據庫,可能發生以下錯誤:ide One or more errors occurred while loading schema information.函數 error 6004: The table 'AdventureWorks.Production.Document' is referenced by a relationship, but cannot be found.工具 這是因爲EF目前還不支持SQL Server 2008中新增的「Hierarchyid」數據類型,目前只有先不用該類型的數據了,暫時將它改成其餘類型。ui |
而後咱們稍等片刻,能夠看到Entity Framework Power Tools已經根據所選數據庫自動爲你生成了數據類、數據庫上下文操做類、對應的映射配置類並添加了數據庫鏈接配置。編碼
咱們先看一下配置文件,能夠看到在配置文件中Entity Framework Power Tools已經自動對數據庫鏈接串進行了配置,添加了名爲「AdventureWorksContext」的數據庫鏈接串:spa
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" /> </configSections> <connectionStrings> <add name="AdventureWorksContext" connectionString="Data Source=.\SQL2008;Initial Catalog=AdventureWorks;Persist Security Info=True;User ID=sa;Password=123;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" /> </startup> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v11.0" /> </parameters> </defaultConnectionFactory> </entityFramework> </configuration>
與此同時,對生成的數據庫上下文操做類「AdventureWorksContext」進行了配置,在構造函數中使用了上面配置的「AdventureWorksContext」數據庫鏈接:.net
using System.Data.Entity; using System.Data.Entity.Infrastructure; using EFPowerTools.Models.Mapping; namespace EFPowerTools.Models { public partial class AdventureWorksContext : DbContext { static AdventureWorksContext() { Database.SetInitializer<AdventureWorksContext>(null); } public AdventureWorksContext() : base("Name=AdventureWorksContext") { } public DbSet<AWBuildVersion> AWBuildVersions { get; set; } public DbSet<DatabaseLog> DatabaseLogs { get; set; } public DbSet<ErrorLog> ErrorLogs { get; set; } public DbSet<OrderDetail> OrderDetails { get; set; } public DbSet<Order> Orders { get; set; } public DbSet<Department> Departments { get; set; } public DbSet<Employee> Employees { get; set; } public DbSet<EmployeeDepartmentHistory> EmployeeDepartmentHistories { get; set; } public DbSet<EmployeePayHistory> EmployeePayHistories { get; set; } public DbSet<JobCandidate> JobCandidates { get; set; } public DbSet<Shift> Shifts { get; set; } public DbSet<Address> Addresses { get; set; } public DbSet<AddressType> AddressTypes { get; set; } public DbSet<BusinessEntity> BusinessEntities { get; set; } public DbSet<BusinessEntityAddress> BusinessEntityAddresses { get; set; } public DbSet<BusinessEntityContact> BusinessEntityContacts { get; set; } public DbSet<ContactType> ContactTypes { get; set; } public DbSet<CountryRegion> CountryRegions { get; set; } public DbSet<EmailAddress> EmailAddresses { get; set; } public DbSet<Password> Passwords { get; set; } public DbSet<Person> People { get; set; } public DbSet<PersonPhone> PersonPhones { get; set; } public DbSet<PhoneNumberType> PhoneNumberTypes { get; set; } public DbSet<StateProvince> StateProvinces { get; set; } public DbSet<BillOfMaterial> BillOfMaterials { get; set; } public DbSet<Culture> Cultures { get; set; } public DbSet<Illustration> Illustrations { get; set; } public DbSet<Location> Locations { get; set; } public DbSet<Product> Products { get; set; } public DbSet<ProductCategory> ProductCategories { get; set; } public DbSet<ProductCostHistory> ProductCostHistories { get; set; } public DbSet<ProductDescription> ProductDescriptions { get; set; } public DbSet<ProductInventory> ProductInventories { get; set; } public DbSet<ProductListPriceHistory> ProductListPriceHistories { get; set; } public DbSet<ProductModel> ProductModels { get; set; } public DbSet<ProductModelIllustration> ProductModelIllustrations { get; set; } public DbSet<ProductModelProductDescriptionCulture> ProductModelProductDescriptionCultures { get; set; } public DbSet<ProductPhoto> ProductPhotoes { get; set; } public DbSet<ProductProductPhoto> ProductProductPhotoes { get; set; } public DbSet<ProductReview> ProductReviews { get; set; } public DbSet<ProductSubcategory> ProductSubcategories { get; set; } public DbSet<ScrapReason> ScrapReasons { get; set; } public DbSet<TransactionHistory> TransactionHistories { get; set; } public DbSet<TransactionHistoryArchive> TransactionHistoryArchives { get; set; } public DbSet<UnitMeasure> UnitMeasures { get; set; } public DbSet<WorkOrder> WorkOrders { get; set; } public DbSet<WorkOrderRouting> WorkOrderRoutings { get; set; } public DbSet<ProductVendor> ProductVendors { get; set; } public DbSet<PurchaseOrderDetail> PurchaseOrderDetails { get; set; } public DbSet<PurchaseOrderHeader> PurchaseOrderHeaders { get; set; } public DbSet<ShipMethod> ShipMethods { get; set; } public DbSet<Vendor> Vendors { get; set; } public DbSet<CountryRegionCurrency> CountryRegionCurrencies { get; set; } public DbSet<CreditCard> CreditCards { get; set; } public DbSet<Currency> Currencies { get; set; } public DbSet<CurrencyRate> CurrencyRates { get; set; } public DbSet<Customer> Customers { get; set; } public DbSet<PersonCreditCard> PersonCreditCards { get; set; } public DbSet<SalesOrderDetail> SalesOrderDetails { get; set; } public DbSet<SalesOrderHeader> SalesOrderHeaders { get; set; } public DbSet<SalesOrderHeaderSalesReason> SalesOrderHeaderSalesReasons { get; set; } public DbSet<SalesPerson> SalesPersons { get; set; } public DbSet<SalesPersonQuotaHistory> SalesPersonQuotaHistories { get; set; } public DbSet<SalesReason> SalesReasons { get; set; } public DbSet<SalesTaxRate> SalesTaxRates { get; set; } public DbSet<SalesTerritory> SalesTerritories { get; set; } public DbSet<SalesTerritoryHistory> SalesTerritoryHistories { get; set; } public DbSet<ShoppingCartItem> ShoppingCartItems { get; set; } public DbSet<SpecialOffer> SpecialOffers { get; set; } public DbSet<SpecialOfferProduct> SpecialOfferProducts { get; set; } public DbSet<Store> Stores { get; set; } public DbSet<vEmployee> vEmployees { get; set; } public DbSet<vEmployeeDepartment> vEmployeeDepartments { get; set; } public DbSet<vEmployeeDepartmentHistory> vEmployeeDepartmentHistories { get; set; } public DbSet<vJobCandidate> vJobCandidates { get; set; } public DbSet<vJobCandidateEducation> vJobCandidateEducations { get; set; } public DbSet<vJobCandidateEmployment> vJobCandidateEmployments { get; set; } public DbSet<vAdditionalContactInfo> vAdditionalContactInfoes { get; set; } public DbSet<vStateProvinceCountryRegion> vStateProvinceCountryRegions { get; set; } public DbSet<vProductAndDescription> vProductAndDescriptions { get; set; } public DbSet<vProductModelCatalogDescription> vProductModelCatalogDescriptions { get; set; } public DbSet<vProductModelInstruction> vProductModelInstructions { get; set; } public DbSet<vVendorWithAddress> vVendorWithAddresses { get; set; } public DbSet<vVendorWithContact> vVendorWithContacts { get; set; } public DbSet<vIndividualCustomer> vIndividualCustomers { get; set; } public DbSet<vPersonDemographic> vPersonDemographics { get; set; } public DbSet<vSalesPerson> vSalesPersons { get; set; } public DbSet<vSalesPersonSalesByFiscalYear> vSalesPersonSalesByFiscalYears { get; set; } public DbSet<vStoreWithAddress> vStoreWithAddresses { get; set; } public DbSet<vStoreWithContact> vStoreWithContacts { get; set; } public DbSet<vStoreWithDemographic> vStoreWithDemographics { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new AWBuildVersionMap()); modelBuilder.Configurations.Add(new DatabaseLogMap()); modelBuilder.Configurations.Add(new ErrorLogMap()); modelBuilder.Configurations.Add(new OrderDetailMap()); modelBuilder.Configurations.Add(new OrderMap()); modelBuilder.Configurations.Add(new DepartmentMap()); modelBuilder.Configurations.Add(new EmployeeMap()); modelBuilder.Configurations.Add(new EmployeeDepartmentHistoryMap()); modelBuilder.Configurations.Add(new EmployeePayHistoryMap()); modelBuilder.Configurations.Add(new JobCandidateMap()); modelBuilder.Configurations.Add(new ShiftMap()); modelBuilder.Configurations.Add(new AddressMap()); modelBuilder.Configurations.Add(new AddressTypeMap()); modelBuilder.Configurations.Add(new BusinessEntityMap()); modelBuilder.Configurations.Add(new BusinessEntityAddressMap()); modelBuilder.Configurations.Add(new BusinessEntityContactMap()); modelBuilder.Configurations.Add(new ContactTypeMap()); modelBuilder.Configurations.Add(new CountryRegionMap()); modelBuilder.Configurations.Add(new EmailAddressMap()); modelBuilder.Configurations.Add(new PasswordMap()); modelBuilder.Configurations.Add(new PersonMap()); modelBuilder.Configurations.Add(new PersonPhoneMap()); modelBuilder.Configurations.Add(new PhoneNumberTypeMap()); modelBuilder.Configurations.Add(new StateProvinceMap()); modelBuilder.Configurations.Add(new BillOfMaterialMap()); modelBuilder.Configurations.Add(new CultureMap()); modelBuilder.Configurations.Add(new IllustrationMap()); modelBuilder.Configurations.Add(new LocationMap()); modelBuilder.Configurations.Add(new ProductMap()); modelBuilder.Configurations.Add(new ProductCategoryMap()); modelBuilder.Configurations.Add(new ProductCostHistoryMap()); modelBuilder.Configurations.Add(new ProductDescriptionMap()); modelBuilder.Configurations.Add(new ProductInventoryMap()); modelBuilder.Configurations.Add(new ProductListPriceHistoryMap()); modelBuilder.Configurations.Add(new ProductModelMap()); modelBuilder.Configurations.Add(new ProductModelIllustrationMap()); modelBuilder.Configurations.Add(new ProductModelProductDescriptionCultureMap()); modelBuilder.Configurations.Add(new ProductPhotoMap()); modelBuilder.Configurations.Add(new ProductProductPhotoMap()); modelBuilder.Configurations.Add(new ProductReviewMap()); modelBuilder.Configurations.Add(new ProductSubcategoryMap()); modelBuilder.Configurations.Add(new ScrapReasonMap()); modelBuilder.Configurations.Add(new TransactionHistoryMap()); modelBuilder.Configurations.Add(new TransactionHistoryArchiveMap()); modelBuilder.Configurations.Add(new UnitMeasureMap()); modelBuilder.Configurations.Add(new WorkOrderMap()); modelBuilder.Configurations.Add(new WorkOrderRoutingMap()); modelBuilder.Configurations.Add(new ProductVendorMap()); modelBuilder.Configurations.Add(new PurchaseOrderDetailMap()); modelBuilder.Configurations.Add(new PurchaseOrderHeaderMap()); modelBuilder.Configurations.Add(new ShipMethodMap()); modelBuilder.Configurations.Add(new VendorMap()); modelBuilder.Configurations.Add(new CountryRegionCurrencyMap()); modelBuilder.Configurations.Add(new CreditCardMap()); modelBuilder.Configurations.Add(new CurrencyMap()); modelBuilder.Configurations.Add(new CurrencyRateMap()); modelBuilder.Configurations.Add(new CustomerMap()); modelBuilder.Configurations.Add(new PersonCreditCardMap()); modelBuilder.Configurations.Add(new SalesOrderDetailMap()); modelBuilder.Configurations.Add(new SalesOrderHeaderMap()); modelBuilder.Configurations.Add(new SalesOrderHeaderSalesReasonMap()); modelBuilder.Configurations.Add(new SalesPersonMap()); modelBuilder.Configurations.Add(new SalesPersonQuotaHistoryMap()); modelBuilder.Configurations.Add(new SalesReasonMap()); modelBuilder.Configurations.Add(new SalesTaxRateMap()); modelBuilder.Configurations.Add(new SalesTerritoryMap()); modelBuilder.Configurations.Add(new SalesTerritoryHistoryMap()); modelBuilder.Configurations.Add(new ShoppingCartItemMap()); modelBuilder.Configurations.Add(new SpecialOfferMap()); modelBuilder.Configurations.Add(new SpecialOfferProductMap()); modelBuilder.Configurations.Add(new StoreMap()); modelBuilder.Configurations.Add(new vEmployeeMap()); modelBuilder.Configurations.Add(new vEmployeeDepartmentMap()); modelBuilder.Configurations.Add(new vEmployeeDepartmentHistoryMap()); modelBuilder.Configurations.Add(new vJobCandidateMap()); modelBuilder.Configurations.Add(new vJobCandidateEducationMap()); modelBuilder.Configurations.Add(new vJobCandidateEmploymentMap()); modelBuilder.Configurations.Add(new vAdditionalContactInfoMap()); modelBuilder.Configurations.Add(new vStateProvinceCountryRegionMap()); modelBuilder.Configurations.Add(new vProductAndDescriptionMap()); modelBuilder.Configurations.Add(new vProductModelCatalogDescriptionMap()); modelBuilder.Configurations.Add(new vProductModelInstructionMap()); modelBuilder.Configurations.Add(new vVendorWithAddressMap()); modelBuilder.Configurations.Add(new vVendorWithContactMap()); modelBuilder.Configurations.Add(new vIndividualCustomerMap()); modelBuilder.Configurations.Add(new vPersonDemographicMap()); modelBuilder.Configurations.Add(new vSalesPersonMap()); modelBuilder.Configurations.Add(new vSalesPersonSalesByFiscalYearMap()); modelBuilder.Configurations.Add(new vStoreWithAddressMap()); modelBuilder.Configurations.Add(new vStoreWithContactMap()); modelBuilder.Configurations.Add(new vStoreWithDemographicMap()); } } }
在項目中咱們還能夠看到Entity Framework Power Tools自動建立了一個Models文件夾,這裏除了「AdventureWorksContext」類還有全部的數據類。在Models文件夾下還有一個「Mapping」文件夾,這裏放了數據類與數據庫的映射配置類,能夠看出Entity Framework Power Tools經過fluent API的方式進行映射細節配置(目前Entity Framework Power Tools還不支持Data Annotations方式),關於配置類的具體細節咱們這裏暫不進行詳細介紹。
下面咱們進行數據查詢:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using EFPowerTools.Models; namespace EFPowerTools { class Program { static void Main(string[] args) { using (var db = new AdventureWorksContext()) { var persons = db.People.Where(p => p.LastName == "Stevens").OrderBy(p=>p.FirstName); foreach(var p in persons) { Console.WriteLine("FirstName:{0},LastName:{1}", p.FirstName, p.LastName); } } } } }
查詢結果:
事實上Entity Framework Power Tools的功能還遠不止這些,例如咱們上面談到Entity Framework Power Tools使用fluent API進行映射配置,而一般狀況下開發人員更喜歡使用Data Annotations方式進行映射約定,那麼此時你就能夠選擇配置本身的模板。
在項目上右鍵選擇Entity Frmaework->Customize Reverse Engineer Templates,此時會看到項目中添加了一個「CodeTemplates」文件夾,裏面存放了Entity Framework Power Tools用於生產相關類文件的T4模板(對於不瞭解T4模板引擎的朋友能夠點擊這裏Lowering the Barriers to Code Generation with T4),若是此時再使用Entity Framework Power Tools進行Code First反向工程操做將使用當前這個文件夾中的模板進行生成。接下來看一下如何進行模板自定義。
首先讓咱們打開Mapping.tt文件,這個文件主要用戶生成配置類,在Entity Framework Power Tools默認生成的代碼中經過fluent API進行表名和數據類名以及屬性名同列名的對應配置,例以下面的代碼:
下面讓咱們修改一下Mapping.tt文件,去掉上面的約束,而改用Data Annotations方式進行約定。首先去掉下圖中選擇的代碼,此時生成的映射類中就再也不出現上圖中選擇的代碼部分:
而後咱們須要修改Entity.tt模板,將數據庫中的表和列的映射聲明到數據類上。先讓咱們將數據類和表作對應,這須要在數據類上添加「Table」聲明,標記出表名和架構名(EF默認會使用dbo架構),在如圖位置添加以下代碼:
<#
var tableName = (string)efHost.TableSet.MetadataProperties["Table"].Value ?? efHost.TableSet.Name;
var conventionTableName = System.Data.Entity.Design.PluralizationServices.PluralizationService
.CreateService(new CultureInfo("en"))
.Pluralize(efHost.EntityType.Name);
var schemaName = (string)efHost.TableSet.MetadataProperties["Schema"].Value;
schemaName = string.IsNullOrWhiteSpace(schemaName)
? "dbo"
: schemaName;
if(schemaName != "dbo" || conventionTableName != tableName)
{
#>
[Table("<#= tableName #>", Schema="<#= schemaName #>")]
<#
}
#>
這段代碼主要處理邏輯是:當架構不是「dbo」或者表名的複數形式同表名不一樣時添加「Table」標記聲明。之因此添加判斷是由於EF的默認使用「dbo」架構而且EF在操做表的時候默認將數據類的複數形式做爲表名。
接下來添加列標記聲明,在如圖位置添加以下代碼便可:
var columnName = efHost.PropertyToColumnMappings[property].Name;
if(code.Escape(property) != columnName)
{
#>
[Column("<#= columnName #>")]
<#
}
這裏只是簡單的對列名和編碼後的列名進行比較,不一樣則添加列標記,不然不添加(EF默認認爲數據類屬性名和表的列名相同)。
因爲剛纔添加的標記屬性類在「System.ComponentModel.DataAnnotations.Schema」 命名空間下,所以最後還須要在模板頭部添加該命名空間:
<#
if (efHost.EntityFrameworkVersion >= new Version(4, 4))
{
#>
using System.ComponentModel.DataAnnotations.Schema;
<#
}
else
{
#>
using System.ComponentModel.DataAnnotations;
<#
}
#>
因爲以前的EF版本中「Table」和「Column」類不在「System.ComponentModel.DataAnnotations.Schema」命名空間而是在 「System.ComponentModel.DataAnnotations」命名空間中,所以這裏咱們還須要添加一個判斷。
今天的內容先到此爲止,關於如何使用fluent API及Data Annotations定義配置類來進行更多的映射控制請關注後面的文章。