.net core 2.0 Code First Fluent API配置

A.net core 2.0新特性支持經過IEntityTypeConfiguration<>添加Code First配置到一個封裝類。sql

新建目標框架爲.NET Core類庫數據庫

image

新建完了之後右鍵點擊程序集,選擇屬性,選擇目標框架爲.NET Core 2.0api

image

 

在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

image

 

在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文件夾,

image

 

在程序包管理控制檯中輸入:Update-Database以完成數據遷移。完成後打開:視圖->SQL Server對象資源管理器,能夠查看比較具體的數據結構。

image

 

這裏着重要看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; }

添加遷移並更新到數據庫

image


 

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; }

 

在程序包管理控制檯中添加遷移並更新到數據庫:

image

 


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);
        }
    }
}

在管理控制檯中添加遷移並更新到數據庫

image 

相關文章
相關標籤/搜索