A.net core 2.0新特性支持經過IEntityTypeConfiguration<>添加Code First配置到一個封裝類。sql
新建目標框架爲.NET Core類庫數據庫
新建完了之後右鍵點擊程序集,選擇屬性,選擇目標框架爲.NET Core 2.0api
在EntityFrameworkCore程序集中添加類User(用戶)、Address(用戶住址)、Book(書)、Author(做者)。這裏不討論各個類設計的合理性和程序架構,主要目的是爲了演示各個類之間的關係配置。數據結構
User和Address類用於演示配置1-0..1關係。User和Book用於演示1-N,即1對多關係。Book和Author用於演示N-N關係,即多對多關係。架構
注意:在EF6.x中,當配置1-0..1關係時,附屬表的主鍵值能夠與主表的主鍵相同,主表對應這裏的User,附屬表對應Address,而因爲篇幅有限,在.net core 2.0中不討論此實現,即每一個表都有本身的主鍵,表關聯都經過外鍵做爲實現。app
User表實現以下框架
using System; namespace EntityFrameworkCore { /// <summary> /// 用戶模型 /// </summary> public sealed class User { public User() { ID = Guid.NewGuid(); TimeCreated = DateTime.Now; } public Guid ID { get; private set; } /// <summary> /// 用戶名稱 /// </summary> public string Name { get; set; } /// <summary> /// 用戶登陸密碼 /// </summary> public string Password { get; set; } /// <summary> /// 用戶建立時間 /// </summary> public DateTime TimeCreated { get; private set; } public Address Address { get; set; } } }
Address表實現以下ide
using System; namespace EntityFrameworkCore { /// <summary> /// 用戶地址模型 /// </summary> public sealed class Address { public Address() { ID = Guid.NewGuid(); TimeCreated = DateTime.Now; } public Guid ID { get; private set; } /// <summary> /// 國家 /// </summary> public string Country { get; set; } /// <summary> /// 省 /// </summary> public string Province { get; set; } /// <summary> /// 城市 /// </summary> public string City { get; set; } /// <summary> /// 區/縣 /// </summary> public string Area { get; set; } /// <summary> /// 街道 /// </summary> public string Street { get; set; } /// <summary> /// 建立時間 /// </summary> public DateTime TimeCreated { get; private set; } /// <summary> /// 用戶ID /// </summary> public Guid UserID { get; set; } public User User { get; set; } } }
Book實現以下工具
using System; using System.Collections.Generic; namespace EntityFrameworkCore { /// <summary> /// 書模型 /// </summary> public sealed class Book { public Book() { ID = Guid.NewGuid(); TimeCreated = DateTime.Now; } public Guid ID { get; private set; } public DateTime TimeCreated { get; private set; } /// <summary> /// 書名 /// </summary> public string Name { get; set; } /// <summary> /// 出版號 /// </summary> public string PublicNo { get; set; } public List<Author> Authors { get; set; } } }
Author實現以下ui
using System; using System.Collections.Generic; namespace EntityFrameworkCore { /// <summary> /// 做者模型 /// </summary> public sealed class Author { public Author() { ID = Guid.NewGuid(); TimeCreated = DateTime.Now; } public Guid ID { get; private set; } public DateTime TimeCreated { get; private set; } /// <summary> /// 做者名字 /// </summary> public string Name { get; set; } public List<Book> Books { get; set; } } }
點擊工具->NuGet包管理器->程序包管理控制檯,在程序包管理控制檯中輸入命令:Install-Package Microsoft.EntityFrameworkCore.SqlServer
在EntityFrameworkCore中添加文件夾ModelConfigs
1-0..1關係配置User—Address:
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkCore.ModelConfigs { public sealed class UserConfig:IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { builder.HasKey(q => q.ID); builder.Property(q => q.Name).HasMaxLength(100).IsRequired(); builder.Property(q => q.Password).HasMaxLength(100).IsRequired(); builder.Property(q => q.TimeCreated).IsRequired(); //使用HasOne和WithOne兩個擴展方法對User表和Address表進行1-1關係配置 builder.HasOne(q => q.Address).WithOne(q => q.User).HasForeignKey<Address>(q => q.UserID); } } }
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkCore.ModelConfigs { public sealed class AddressConfig: IEntityTypeConfiguration<Address> { public void Configure(EntityTypeBuilder<Address> builder) { builder.HasKey(q => q.ID); builder.Property(q => q.Area).HasMaxLength(100).IsRequired(); builder.Property(q => q.City).HasMaxLength(100).IsRequired(); builder.Property(q => q.Country).HasMaxLength(100).IsRequired(); builder.Property(q => q.Province).HasMaxLength(100).IsRequired(); builder.Property(q => q.Street).HasMaxLength(200).IsRequired(); builder.Property(q => q.TimeCreated).IsRequired(); builder.Property(q => q.UserID).IsRequired(); } } }
UserConfig和AddressConfig分別對User表數據和Address表數據進行了配置,添加FluentApiDemoDbContext類並繼承DbContext,微軟官方解釋DbContext實例是一個帶有數據庫的會話而且能用於添加和查詢實體。FluentApiDemoDbContext類代碼以下:
using System; using System.Linq; using System.Reflection; using Microsoft.EntityFrameworkCore; namespace EntityFrameworkCore { public class FluentApiDemoDbContext : DbContext { public FluentApiDemoDbContext(DbContextOptions<FluentApiDemoDbContext> options) : base(options) { } public DbSet<User> User { get; set; } public DbSet<Address> Address { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var typesToRegister = Assembly.GetExecutingAssembly().GetTypes() .Where(q => q.GetInterface(typeof(IEntityTypeConfiguration<>).FullName) != null); foreach (var type in typesToRegister) { dynamic configurationInstance = Activator.CreateInstance(type); modelBuilder.ApplyConfiguration(configurationInstance); } } } }
若是這裏直接把EntityFrameworkCore設爲啓動項,當在程序包管理控制檯中輸入:Update-Database時將報錯:Unable to create an object of type 'FluentApiDemoDbContext'. Add an implementation of 'IDesignTimeDbContextFactory<FluentApiDemoDbContext>' to the project, or see https://go.microsoft.com/fwlink/?linkid=851728 for additional patterns supported at design time.提示須要添加一個IDesignTimeDbContextFactory<FluentApiDemoDbContext>的實現,這裏若是是用Console寫Demo,那麼能夠自行實現該接口,在該文中我將添加WebApi做爲啓用項。Startup.cs內容以下:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using EntityFrameworkCore; namespace WebApi { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); var connection = @"Server=(localdb)\mssqllocaldb;Database=FluentApiDemoDb;Trusted_Connection=True;"; services.AddDbContextPool<FluentApiDemoDbContext>(options => options.UseSqlServer(connection)); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); } } }
配置之後將該WebApi項目設置爲啓動項,在程序包管理控制檯中輸入:Add-Migration Initial以啓動遷移。完成之後,項目會添加Migraions文件夾,
在程序包管理控制檯中輸入:Update-Database以完成數據遷移。完成後打開:視圖->SQL Server對象資源管理器,能夠查看比較具體的數據結構。
這裏着重要看Address表中的UserID,UserID作爲Address表的外鍵是非空的,按照文章開頭說的1-0..1關係,這裏只實現了1-1,並無實現1-0關係,更改AddressConfig中的關係配置爲:
… builder.HasOne(q => q.User).WithOne(q => q.Address).HasForeignKey<Address>(q => q.UserID).IsRequired(false);
並更改Address中的代碼爲:
… public Guid? UserID { get; set; }
添加遷移並更新到數據庫
1-N關係配置,1個用戶擁有多本書。在User表中添加
…
public List<Book> Books { get; set; }
Book表中添加
…
public Guid? UserID { get; set; } public User User { get; set; }
在ModelConfigs中添加BookConfig
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkCore.ModelConfigs { public sealed class BookConfig: IEntityTypeConfiguration<Book> { public void Configure(EntityTypeBuilder<Book> builder) { builder.HasKey(q => q.ID); builder.Property(q => q.Name).HasMaxLength(100).IsRequired(); builder.Property(q => q.PublicNo).HasMaxLength(100).IsRequired(); builder.HasOne(q => q.User).WithMany(q => q.Books).HasForeignKey(q => q.UserID).IsRequired(false); } } }
在FluentApiDemoDbContext中註冊實體
…
public DbSet<Book> Book { get; set; }
在程序包管理控制檯中添加遷移並更新到數據庫:
N-N關係配置,當使用EF6.x時,配置多對多關係,EF會自動生成中間表,在.net core中,須要手動添加關係表,實際上在EF6.x中當配置多對多關係時,也能夠經過中間表配置1對多的方式實現多對多。
這裏經過Book表和Author表實現多對多關係配置。一個做者能夠有多本書,一本書有多個做者。
首先添加關係表AuthorsInBooks
using System; namespace EntityFrameworkCore { public sealed class AuthorsInBooks { public Guid BookID { get; set; } public Book Book { get; set; } public Guid AuthorID { get; set; } public Author Author { get; set; } } }
同時更改Books表
public List<Author> Authors { get; set; } 改成 public List<AuthorsInBooks> AuthorsInBooks { get; set; }
同理更改Author表
public List<Book> Books { get; set; } 改成 public List<AuthorsInBooks> AuthorsInBooks { get; set; }
添加AuthorsConfig
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkCore.ModelConfigs { public sealed class AuthorConfig:IEntityTypeConfiguration<Author> { public void Configure(EntityTypeBuilder<Author> builder) { builder.HasKey(q => q.ID); builder.Property(q => q.Name).HasMaxLength(100).IsRequired(); builder.Property(q => q.TimeCreated).IsRequired(); } } }
並在FluentApiDemoDbContext中註冊Author
…
public DbSet<Author> Author { get; set; }
接下來添加AuthorsInBooksConfig
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; namespace EntityFrameworkCore.ModelConfigs { public sealed class AuthorsInBooksConfig:IEntityTypeConfiguration<AuthorsInBooks> { public void Configure(EntityTypeBuilder<AuthorsInBooks> builder) { builder.HasKey(q => new { q.AuthorID, q.BookID }); builder.HasOne(q => q.Author).WithMany(q => q.AuthorsInBooks).HasForeignKey(q => q.AuthorID); builder.HasOne(q => q.Book).WithMany(q => q.AuthorsInBooks).HasForeignKey(q => q.BookID); } } }
在管理控制檯中添加遷移並更新到數據庫