Apworks框架實戰(六):使用基於Entity Framework的倉儲基礎結構

在前面的章節中,咱們已經設計了一個簡單的領域模型,接下來咱們但願可以實現領域模型的持久化及查詢。在Apworks中,實現了面向Entity Framework、NHibernate以及MongoDB的倉儲基礎結構。在本章節中,我將向你們介紹如何在Apworks中使用基於Entity Framework的倉儲機制。web

搭建基於Entity Framework的基礎結構

在使用Apworks提供的倉儲服務以前,咱們首先須要搭建好基於Entity Framework的基礎結構,以便接下來的Apworks可以使用這些基礎結構功能,並利用Entity Framework實現領域模型對象生命週期的管理。數據庫

從DbContext開始

咱們採用Entity Framework Code First的編程模型,所以,咱們將從DbContext開始入手,爲Entity Framework倉儲機制的使用作好準備工做。編程

首先,在【EasyMemo.Repositories】項目上單擊鼠標右鍵,選擇【管理NuGet程序包】選項。在彈出的【管理NuGet程序包】的【搜索聯機】文本框中,輸入關鍵字【apworks】。在過濾的列表中,找到【Apworks.Repositories.EntityFramework】,而後單擊【安裝】按鈕。api

image

說明:安裝該程序包也會順帶將其所依賴的程序包一併安裝到【EasyMemo.Repositories】項目中,這些程序包包括:瀏覽器

  • Apworks 2.5.5662.37915
  • Castle.Core 3.3.1
  • EntityFramework 6.1.1

接下來,在【EasyMemo.Repositories】項目中,新建一個名爲EasyMemoContext的類,該類從System.Data.Entity.DbContext類繼承,代碼以下:app

public class EasyMemoContext : DbContext
{
    public EasyMemoContext()
        : base("EasyMemoDB")
    {
        
    }

    public DbSet<Account> Accounts { get; set; }

    public DbSet<Role> Roles { get; set; }

    public DbSet<Memo> Memos { get; set; }
}

這就是標準的Entity Framework Code First的用法,不過,Apworks的最佳實踐中建議,此處僅對聚合根定義DbSet屬性,這樣能使DbContext的定義變得很是簡潔直觀。框架

下一步就是針對領域模型中的實體定義一些類型/數據庫映射。根據標準的Entity Framework使用方法,咱們能夠定義一系列繼承於EntityTypeConfiguration泛型類的子類,在這些子類中定義映射規則,並在EasyMemoContext的OnModelCreating重載方法中將這些子類的實例添加到Configurations集合裏;或者也能夠直接在OnModelCreating方法中定義映射規則。我仍是比較偏向於前面這種方式,即針對每一個須要配置映射的實體,都建立一個繼承於EntityTypeConfiguration的子類,雖然看起來會有不少額外的類定義,但這樣作會使得代碼結構有着更好的可讀性。例如,針對Account對象,咱們能夠定義映射配置類型以下:ide

public class AccountEntityConfiguration : EntityTypeConfiguration<Account>
{
    public AccountEntityConfiguration()
    {
        ToTable("Accounts");
        HasKey(x => x.ID);
        Property(x => x.ID)
            .IsRequired()
            .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        Property(x => x.DateCreated).IsRequired();
        Property(x => x.DateLastLogon).IsOptional();
        Property(x => x.DisplayName)
            .IsRequired()
            .IsUnicode()
            .HasMaxLength(32);
        Property(x => x.Email)
            .IsRequired()
            .IsUnicode()
            .HasMaxLength(64);
        Property(x => x.IsDeleted).IsOptional();
        Property(x => x.Name).IsRequired()
            .IsUnicode()
            .HasMaxLength(16);
        Property(x => x.Password).IsRequired()
            .IsUnicode()
            .HasMaxLength(4096);
    }
}

而後將該類的實例添加到OnModelCreating重載方法中:ui

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new AccountEntityConfiguration());
}

OK,接下來使用相似的方法針對領域模型中必要的實體類型定義映射配置類,並依次將這些類的實例添加到OnModelCreating重載方法中。限於篇幅,在此就不一一列出代碼了,您能夠在本章節結尾部分點擊下載代碼的連接,把源代碼下載到本地做參考。this

設置數據庫初始化策略

Entity Framework自己支持如下幾種數據庫初始化策略:

  1. MigrateDatabaseToLatestVersion:使用Code First數據庫遷移策略,將數據庫更新到最新版本
  2. NullDatabaseInitializer:一個什麼都不幹的數據庫初始化器
  3. CreateDatabaseIfNotExists:顧名思義,若是數據庫不存在則新建數據庫
  4. DropCreateDatabaseAlways:不管數據庫是否存在,始終重建數據庫
  5. DropCreateDatabaseIfModelChanges:僅當領域模型發生變化時才重建數據庫

在實際應用當中,咱們能夠直接使用以上數據庫初始化策略,在調用Database對象的Initialize方法時,Entity Framework就會根據所選擇的初始化策略以及上面的映射配置信息來初始化數據庫。爲了演示目的,咱們但願可以在數據庫初始化的同時,爲咱們準備一些數據,以便對從此的內容進行介紹,所以,咱們能夠自定義一套數據庫初始化策略,並在其中將所需的數據寫入數據庫。

首先,在【EasyMemo.Repositories】項目中,新建一個名爲DatabaseInitializeStrategy的類,並使其繼承DropCreateDatabaseIfModelChanges類型:

public class DatabaseInitializeStrategy 
    : DropCreateDatabaseIfModelChanges<EasyMemoContext>
{
}

而後,在該類型中重載Seed方法,添加以下代碼:

public class DatabaseInitializeStrategy 
    : DropCreateDatabaseIfModelChanges<EasyMemoContext>
{
    protected override void Seed(EasyMemoContext context)
    {
        var adminPermission = new Permission
        {
            Privilege = Privilege.SystemAdministration,
            Value = PermissionValue.Allow
        };

        var administrators = new Role
        {
            Name = "系統管理員",
            Description = "執行系統管理任務的一組帳戶",
            Permissions = new List<Permission> {adminPermission}
        };

        var administrator = new Account
        {
            DateCreated = DateTime.UtcNow,
            DisplayName = "管理員",
            Email = "admin@easymemo.com",
            Name = "admin",
            Password = "admin",
            Roles = new List<Role> {administrators}
        };

        context.Accounts.Add(administrator);

        base.Seed(context);
    }
}

因而,咱們就有了本身的數據庫初始化策略,下一步就是在EasyMemo的系統中使用這個策略。

運行咱們的代碼

打開【EasyMemo.Services】項目,以上述相同的方法,經過【管理NuGet程序包】功能,添加對【Apworks.Repositories.EntityFramework】程序包的引用。而後,在Appp_Start目錄下,新建一個名爲DatabaseConfig的類:

image

該類的代碼以下:

public static class DatabaseConfig
{
    public static void Initialize()
    {
        Database.SetInitializer(new DatabaseInitializeStrategy());
        new EasyMemoContext().Database.Initialize(true);
    }
}

接下來,打開【EasyMemo.Services】項目下的Global.asax.cs文件,向Application_Start方法添加對DatabaseConfig.Initialize的調用:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        DatabaseConfig.Initialize();
    }
}

打開【EasyMemo.Services】項目的web.config文件,找到其中的entityFramework節點,對該節點進行配置,使得Entity Framework可以使用您所指定的SQL Server數據庫:

<entityFramework>
  <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
    <parameters>
       <parameter value="Data Source=localhost; Initial Catalog=EasyMemoDB; Integrated Security=True; Connect Timeout=120; MultipleActiveResultSets=True" />
    </parameters>
  </defaultConnectionFactory>
  <providers>
    <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  </providers>
</entityFramework>

如今,請將【EasyMemo.Services】項目設置爲啓動項目,而後直接按F5,稍等片刻,當瀏覽器出現以下畫面後,咱們就能夠到SQL Server中找到由Entity Framework自動產生的數據庫了:

image

 

打開【Microsoft SQL Server Management Studio】,鏈接到所配置的數據庫實例,咱們能夠看到EasyMemoDB已經出如今數據庫列表中:

image

 

而且能夠查詢到咱們預先準備好的數據:

image

由Entity Framework自動產生的數據庫結構以下:

image

固然,目前咱們無需對這個數據模型關注太多,畢竟咱們不打算面向數據庫編程。

開始使用基於Entity Framework的Apworks倉儲服務

在使用Apworks倉儲服務以前,咱們首先須要對Apworks的整個運行環境進行配置。基於以前的分層結構的討論,EasyMemo.Services項目是一個位於服務端的RESTful API項目,它由ASP.NET Web API 2.0實現。所以,針對Apworks框架運行環境的配置也會在這個項目中發生。爲了可以讓Web API控制器可以獲得Apworks倉儲及其上下文的實例,咱們採用了IoC技術,並選擇Microsoft Unity做爲依賴注入框架,這也是Apworks框架目前支持的惟一一種依賴注入框架。固然,Apworks的依賴注入系統是能夠擴展的,您能夠根據本身項目須要對其進行擴展,使其可以支持多種主流的依賴注入框架。

配置Apworks的運行環境

首先,經過【管理NuGet程序包】,向【EasyMemo.Services】項目中添加如下程序包引用:

  1. Apworks.ObjectContainers.Unity:Apworks對Unity的支持庫
  2. Unity.WebAPI:Unity對ASP.NET Web API的支持,它可使得ASP.NET Web API可以使用Unity做爲依賴注入框架

接下來,與以前添加DatabaseConfig類同樣,在【EasyMemo.Services】項目的【App_Start】文件夾下,新建一個名爲ApworksConfig的靜態類,內容以下:

using Apworks.Application;
using Apworks.Config.Fluent;
using Apworks.Repositories;
using Apworks.Repositories.EntityFramework;
using EasyMemo.Repositories;
using Microsoft.Practices.Unity;
using Unity.WebApi;


public static class ApworksConfig
{
    public static void Initialize()
    {
        AppRuntime
            .Instance
            .ConfigureApworks()
            .UsingUnityContainerWithDefaultSettings()
            .Create((sender, e) =>
            {
                var unityContainer = e.ObjectContainer.GetWrappedContainer<UnityContainer>();
                unityContainer.RegisterInstance(new EasyMemoContext(), new PerResolveLifetimeManager())
                    .RegisterType<IRepositoryContext, EntityFrameworkRepositoryContext>(
                        new HierarchicalLifetimeManager(),
                        new InjectionConstructor(new ResolvedParameter<EasyMemoContext>()))
                    .RegisterType(typeof (IRepository<>), typeof (EntityFrameworkRepository<>));

                GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(unityContainer);
            })
            .Start();
    }
}

注意:這裏採用的是Fluent Interface(流暢接口)的配置方式。Apworks同時也支持基於web.config/app.config的配置方式,從此有機會我再介紹這部份內容。

而後,一樣地,在Global.asax.cs文件的Application_Start方法中,調用上述代碼:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
        DatabaseConfig.Initialize();
        ApworksConfig.Initialize();
    }
}

OK,Apworks的運行環境配置基本上就算完成了。接下來,讓咱們新建一個簡單的RESTful API,來跑通整個流程。

開始咱們的ASP.NET Web API之旅

在【EasyMemo.Services】項目中,找到【Controllers】目錄,單擊鼠標右鍵,在右鍵菜單中選擇【添加 –> 控制器】。在彈出的【添加基架】對話框中,選擇【Web API 2控制器 - 空】:

image

在彈出的【添加控制器】對話框的【控制器名稱】一欄,填入【AccountsController】:

image

在單擊【添加】按鈕後,Visual Studio會打開AccountsController的代碼編輯界面。此時,咱們能夠向AccountsController類添加如下代碼:

[RoutePrefix("api/accounts")]
public class AccountsController : ApiController
{
    private readonly IRepository<Account> accountRepository;
    private readonly IRepositoryContext unitOfWork;

    public AccountsController(IRepositoryContext unitOfWork, IRepository<Account> accountRepository)
    {
        this.accountRepository = accountRepository;
        this.unitOfWork = unitOfWork;
    }

    [HttpGet]
    [Route("name/{name}")]
    public IHttpActionResult GetByName(string name)
    {
        var account = this.accountRepository.Find(Specification<Account>.Eval(acct => acct.Name == name));
        if (account != null)
        {
            return Ok(new
            {
                account.Name,
                account.DisplayName,
                account.Email,
                account.DateCreated,
                account.DateLastLogon
            });
        }
        throw new Exception(string.Format("The account '{0}' does not exist.", name));
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            unitOfWork.Dispose();
        }
        base.Dispose(disposing);
    }
}

代碼還算簡潔吧?讓咱們再次啓動【EasyMemo.Services】項目:將該項目設置爲啓動項目,而後直接按F5,在一個與上面相同的【403.14 – Forbidden】頁面出來後,在瀏覽器中輸入:

http://localhost:30295/api/accounts/name/admin

此時,你就能看到這個RESTful API返回的結果:它返回了admin這個帳戶的詳細信息:

image

總結

本文詳細介紹瞭如何在Apworks框架中使用Entity Framework併爲一個ASP.NET Web API的RESTful服務提供倉儲及其上下文的基礎結構。從下一講開始,咱們會重點討論ASP.NET Web API實現的方方面面,包括異常處理、認證與受權、數據傳輸對象與視圖模型等。

源代碼下載

【單擊此處】下載截止到本文爲止的EasyMemo解決方案源代碼。

相關文章
相關標籤/搜索