在前面的章节中,我们已经设计了一个简单的领域模型,接下来我们希望能够实现领域模型的持久化及查询。在Apworks中,实现了面向Entity Framework、NHibernate以及MongoDB的仓储基础结构。在本章节中,我将向大家介绍如何在Apworks中使用基于Entity Framework的仓储机制。

搭建基于Entity Framework的基础结构

在使用Apworks提供的仓储服务之前,我们首先需要搭建好基于Entity Framework的基础结构,以便接下来的Apworks能够使用这些基础结构功能,并利用Entity Framework实现领域模型对象生命周期的管理。

从DbContext开始

我们采用Entity Framework Code First的编程模型,因此,我们将从DbContext开始入手,为Entity Framework仓储机制的使用做好准备工作。

首先,在【EasyMemo.Repositories】项目上单击鼠标右键,选择【管理NuGet程序包】选项。在弹出的【管理NuGet程序包】的【搜索联机】文本框中,输入关键字【apworks】。在过滤的列表中,找到【Apworks.Repositories.EntityFramework】,然后单击【安装】按钮。

说明:安装该程序包也会顺带将其所依赖的程序包一并安装到【EasyMemo.Repositories】项目中,这些程序包包括:

  • Apworks 2.5.5662.37915
  • Castle.Core 3.3.1
  • EntityFramework 6.1.1

接下来,在【EasyMemo.Repositories】项目中,新建一个名为EasyMemoContext的类,该类从System.Data.Entity.DbContext类继承,代码如下:

  1. public class EasyMemoContext : DbContext
  2. {
  3. public EasyMemoContext()
  4. : base("EasyMemoDB")
  5. {
  6.  
  7. }
  8.  
  9. public DbSet<Account> Accounts { get; set; }
  10.  
  11. public DbSet<Role> Roles { get; set; }
  12.  
  13. public DbSet<Memo> Memos { get; set; }
  14. }

这就是标准的Entity Framework Code First的用法,不过,Apworks的最佳实践中建议,此处仅对聚合根定义DbSet属性,这样能使DbContext的定义变得非常简洁直观。

下一步就是针对领域模型中的实体定义一些类型/数据库映射。根据标准的Entity Framework使用方法,我们可以定义一系列继承于EntityTypeConfiguration泛型类的子类,在这些子类中定义映射规则,并在EasyMemoContext的OnModelCreating重载方法中将这些子类的实例添加到Configurations集合里;或者也可以直接在OnModelCreating方法中定义映射规则。我还是比较偏向于前面这种方式,即针对每个需要配置映射的实体,都创建一个继承于EntityTypeConfiguration的子类,虽然看起来会有很多额外的类定义,但这样做会使得代码结构有着更好的可读性。例如,针对Account对象,我们可以定义映射配置类型如下:

  1. public class AccountEntityConfiguration : EntityTypeConfiguration<Account>
  2. {
  3. public AccountEntityConfiguration()
  4. {
  5. ToTable("Accounts");
  6. HasKey(x => x.ID);
  7. Property(x => x.ID)
  8. .IsRequired()
  9. .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
  10. Property(x => x.DateCreated).IsRequired();
  11. Property(x => x.DateLastLogon).IsOptional();
  12. Property(x => x.DisplayName)
  13. .IsRequired()
  14. .IsUnicode()
  15. .HasMaxLength(32);
  16. Property(x => x.Email)
  17. .IsRequired()
  18. .IsUnicode()
  19. .HasMaxLength(64);
  20. Property(x => x.IsDeleted).IsOptional();
  21. Property(x => x.Name).IsRequired()
  22. .IsUnicode()
  23. .HasMaxLength(16);
  24. Property(x => x.Password).IsRequired()
  25. .IsUnicode()
  26. .HasMaxLength(4096);
  27. }
  28. }

然后将该类的实例添加到OnModelCreating重载方法中:

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

OK,接下来使用类似的方法针对领域模型中必要的实体类型定义映射配置类,并依次将这些类的实例添加到OnModelCreating重载方法中。限于篇幅,在此就不一一列出代码了,您可以在本章节结尾部分点击下载代码的链接,把源代码下载到本地作参考。

设置数据库初始化策略

Entity Framework本身支持以下几种数据库初始化策略:

  1. MigrateDatabaseToLatestVersion:使用Code First数据库迁移策略,将数据库更新到最新版本
  2. NullDatabaseInitializer:一个什么都不干的数据库初始化器
  3. CreateDatabaseIfNotExists:顾名思义,如果数据库不存在则新建数据库
  4. DropCreateDatabaseAlways:无论数据库是否存在,始终重建数据库
  5. DropCreateDatabaseIfModelChanges:仅当领域模型发生变化时才重建数据库

在实际应用当中,我们可以直接使用以上数据库初始化策略,在调用Database对象的Initialize方法时,Entity Framework就会根据所选择的初始化策略以及上面的映射配置信息来初始化数据库。为了演示目的,我们希望能够在数据库初始化的同时,为我们准备一些数据,以便对今后的内容进行介绍,因此,我们可以自定义一套数据库初始化策略,并在其中将所需的数据写入数据库。

首先,在【EasyMemo.Repositories】项目中,新建一个名为DatabaseInitializeStrategy的类,并使其继承DropCreateDatabaseIfModelChanges类型:

  1. public class DatabaseInitializeStrategy
  2. : DropCreateDatabaseIfModelChanges<EasyMemoContext>
  3. {
  4. }

然后,在该类型中重载Seed方法,添加如下代码:

  1. public class DatabaseInitializeStrategy
  2. : DropCreateDatabaseIfModelChanges<EasyMemoContext>
  3. {
  4. protected override void Seed(EasyMemoContext context)
  5. {
  6. var adminPermission = new Permission
  7. {
  8. Privilege = Privilege.SystemAdministration,
  9. Value = PermissionValue.Allow
  10. };
  11.  
  12. var administrators = new Role
  13. {
  14. Name = "系统管理员",
  15. Description = "执行系统管理任务的一组账户",
  16. Permissions = new List<Permission> {adminPermission}
  17. };
  18.  
  19. var administrator = new Account
  20. {
  21. DateCreated = DateTime.UtcNow,
  22. DisplayName = "管理员",
  23. Email = "admin@easymemo.com",
  24. Name = "admin",
  25. Password = "admin",
  26. Roles = new List<Role> {administrators}
  27. };
  28.  
  29. context.Accounts.Add(administrator);
  30.  
  31. base.Seed(context);
  32. }
  33. }

于是,我们就有了自己的数据库初始化策略,下一步就是在EasyMemo的系统中使用这个策略。

运行我们的代码

打开【EasyMemo.Services】项目,以上述相同的方法,通过【管理NuGet程序包】功能,添加对【Apworks.Repositories.EntityFramework】程序包的引用。然后,在Appp_Start目录下,新建一个名为DatabaseConfig的类:

该类的代码如下:

  1. public static class DatabaseConfig
  2. {
  3. public static void Initialize()
  4. {
  5. Database.SetInitializer(new DatabaseInitializeStrategy());
  6. new EasyMemoContext().Database.Initialize(true);
  7. }
  8. }

接下来,打开【EasyMemo.Services】项目下的Global.asax.cs文件,向Application_Start方法添加对DatabaseConfig.Initialize的调用:

  1. public class WebApiApplication : System.Web.HttpApplication
  2. {
  3. protected void Application_Start()
  4. {
  5. GlobalConfiguration.Configure(WebApiConfig.Register);
  6. DatabaseConfig.Initialize();
  7. }
  8. }

打开【EasyMemo.Services】项目的web.config文件,找到其中的entityFramework节点,对该节点进行配置,使得Entity Framework能够使用您所指定的SQL Server数据库:

  1. <entityFramework>
  2. <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
  3. <parameters>
  4. <parameter value="Data Source=localhost; Initial Catalog=EasyMemoDB; Integrated Security=True; Connect Timeout=120; MultipleActiveResultSets=True" />
  5. </parameters>
  6. </defaultConnectionFactory>
  7. <providers>
  8. <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
  9. </providers>
  10. </entityFramework>

现在,请将【EasyMemo.Services】项目设置为启动项目,然后直接按F5,稍等片刻,当浏览器出现如下画面后,我们就可以到SQL Server中找到由Entity Framework自动产生的数据库了:

 

打开【Microsoft SQL Server Management Studio】,连接到所配置的数据库实例,我们可以看到EasyMemoDB已经出现在数据库列表中:

 

并且可以查询到我们预先准备好的数据:

由Entity Framework自动产生的数据库结构如下:

当然,目前我们无需对这个数据模型关注太多,毕竟我们不打算面向数据库编程。

开始使用基于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的静态类,内容如下:

  1. using Apworks.Application;
  2. using Apworks.Config.Fluent;
  3. using Apworks.Repositories;
  4. using Apworks.Repositories.EntityFramework;
  5. using EasyMemo.Repositories;
  6. using Microsoft.Practices.Unity;
  7. using Unity.WebApi;
  8.  
  9. public static class ApworksConfig
  10. {
  11. public static void Initialize()
  12. {
  13. AppRuntime
  14. .Instance
  15. .ConfigureApworks()
  16. .UsingUnityContainerWithDefaultSettings()
  17. .Create((sender, e) =>
  18. {
  19. var unityContainer = e.ObjectContainer.GetWrappedContainer<UnityContainer>();
  20. unityContainer.RegisterInstance(new EasyMemoContext(), new PerResolveLifetimeManager())
  21. .RegisterType<IRepositoryContext, EntityFrameworkRepositoryContext>(
  22. new HierarchicalLifetimeManager(),
  23. new InjectionConstructor(new ResolvedParameter<EasyMemoContext>()))
  24. .RegisterType(typeof (IRepository<>), typeof (EntityFrameworkRepository<>));
  25.  
  26. GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(unityContainer);
  27. })
  28. .Start();
  29. }
  30. }

注意:这里采用的是Fluent Interface(流畅接口)的配置方式。Apworks同时也支持基于web.config/app.config的配置方式,今后有机会我再介绍这部分内容。

然后,同样地,在Global.asax.cs文件的Application_Start方法中,调用上述代码:

  1. public class WebApiApplication : System.Web.HttpApplication
  2. {
  3. protected void Application_Start()
  4. {
  5. GlobalConfiguration.Configure(WebApiConfig.Register);
  6. DatabaseConfig.Initialize();
  7. ApworksConfig.Initialize();
  8. }
  9. }

OK,Apworks的运行环境配置基本上就算完成了。接下来,让我们新建一个简单的RESTful API,来跑通整个流程。

开始我们的ASP.NET Web API之旅

在【EasyMemo.Services】项目中,找到【Controllers】目录,单击鼠标右键,在右键菜单中选择【添加 –> 控制器】。在弹出的【添加基架】对话框中,选择【Web API 2控制器 - 空】:

在弹出的【添加控制器】对话框的【控制器名称】一栏,填入【AccountsController】:

在单击【添加】按钮后,Visual Studio会打开AccountsController的代码编辑界面。此时,我们可以向AccountsController类添加以下代码:

  1. [RoutePrefix("api/accounts")]
  2. public class AccountsController : ApiController
  3. {
  4. private readonly IRepository<Account> accountRepository;
  5. private readonly IRepositoryContext unitOfWork;
  6.  
  7. public AccountsController(IRepositoryContext unitOfWork, IRepository<Account> accountRepository)
  8. {
  9. this.accountRepository = accountRepository;
  10. this.unitOfWork = unitOfWork;
  11. }
  12.  
  13. [HttpGet]
  14. [Route("name/{name}")]
  15. public IHttpActionResult GetByName(string name)
  16. {
  17. var account = this.accountRepository.Find(Specification<Account>.Eval(acct => acct.Name == name));
  18. if (account != null)
  19. {
  20. return Ok(new
  21. {
  22. account.Name,
  23. account.DisplayName,
  24. account.Email,
  25. account.DateCreated,
  26. account.DateLastLogon
  27. });
  28. }
  29. throw new Exception(string.Format("The account '{0}' does not exist.", name));
  30. }
  31.  
  32. protected override void Dispose(bool disposing)
  33. {
  34. if (disposing)
  35. {
  36. unitOfWork.Dispose();
  37. }
  38. base.Dispose(disposing);
  39. }
  40. }

代码还算简洁吧?让我们再次启动【EasyMemo.Services】项目:将该项目设置为启动项目,然后直接按F5,在一个与上面相同的【403.14 – Forbidden】页面出来后,在浏览器中输入:

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

此时,你就能看到这个RESTful API返回的结果:它返回了admin这个账户的详细信息:

总结

本文详细介绍了如何在Apworks框架中使用Entity Framework并为一个ASP.NET Web API的RESTful服务提供仓储及其上下文的基础结构。从下一讲开始,我们会重点讨论ASP.NET Web API实现的方方面面,包括异常处理、认证与授权、数据传输对象与视图模型等。

源代码下载

【单击此处】下载截止到本文为止的EasyMemo解决方案源代码。

Apworks框架实战(六):使用基于Entity Framework的仓储基础结构的更多相关文章

  1. 在Apworks数据服务中使用基于Entity Framework Core的仓储(Repository)实现

    <在ASP.NET Core中使用Apworks快速开发数据服务>一文中,我介绍了如何使用Apworks框架的数据服务来快速构建用于查询和管理数据模型的RESTful API,通过该文的介 ...

  2. Apworks框架实战

    Apworks框架实战(一):Apworks到底是什么? Apworks框架实战(二):开始使用 Apworks框架实战(三):单元测试与持续集成 Apworks框架实战(四):使用Visual St ...

  3. Apworks框架实战(五):EasyMemo的领域模型设计

    在上一讲中,我们已经新建了一个聚合根对象Account,并已经可以开始设计领域模型了.在这一讲中,我们会着重介绍EasyMemo领域模型的分析和设计,并引入Visual Studio Ultimate ...

  4. Apworks框架实战(一):Apworks到底是什么?

    简介 Apworks是一款基于Microsoft .NET的面向领域驱动的企业级应用程序开发框架,它适用于以领域模型为核心的企业级系统的开发和集成.Apworks不仅能够很好地支持经典的分层架构,而且 ...

  5. 创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表

    创建ASP.NET Core MVC应用程序(3)-基于Entity Framework Core(Code First)创建MySQL数据库表 创建数据模型类(POCO类) 在Models文件夹下添 ...

  6. 基于Entity Framework的自定义分页,增删改的通用实现

    简介 之前写个一个基于Dapper的分页实现,现在再来写一个基于Entity Framework的分页实现,以及增删改的通用实现. 代码 还是先上代码:https://github.com/jinwe ...

  7. Entity FrameWork(实体框架)是以ADO.NET Entity FrameWork ,简称为EF

    Entity FrameWork(实体框架)是以ADO.NET Entity FrameWork ,简称为EF Entity FrameWork的特点 1.支持多种数据库(MSSQL.Oracle.M ...

  8. 基于Entity Framework 6的框架Nido Framework

    随着 Entity Framework 最新主版本 EF6 的推出,Microsoft 对象关系映射 (ORM) 工具达到了新的专业高度,与久负盛名的 .NET ORM 工具相比已不再是门外汉. EF ...

  9. Apworks框架实战(四):使用Visual Studio开发面向经典分层架构的应用程序:从EasyMemo案例开始

    时隔一年,继续我们的Apworks框架之旅.在接下来的文章中,我将逐渐向大家介绍如何在Visual Studio中结合Apworks框架,使用ASP.NET Web API和MVC来开发面向经典分层架 ...

随机推荐

  1. 【AutoMapper官方文档】DTO与Domin Model相互转换(上)

    写在前面 AutoMapper目录: [AutoMapper官方文档]DTO与Domin Model相互转换(上) [AutoMapper官方文档]DTO与Domin Model相互转换(中) [Au ...

  2. C# 中参数验证方式的演变

    一般在写方法的时候,第一步就是进行参数验证,这也体现了编码者的细心和缜密,但是在很多时候这个过程很枯燥和乏味,比如在拿到一个API设计文档的时候,通常会规定类型参数是否允许为空,如果是字符可能有长度限 ...

  3. 06.SQLServer性能优化之---数据库级日记监控

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 之前说了一下数据库怎么发邮件:http://www.cnblogs.com/duniti ...

  4. IE的F12开发人员工具不显示问题

    按下F12之后,开发人员工具在桌面上看不到,但是任务栏里有显示.将鼠标放在任务栏的开发人员工具上,出现一片透明的区域,选中之后却出不来.将鼠标移动到开发人员工具的缩略图上,右键-最大化,工具就全屏出现 ...

  5. 基于AOP的MVC拦截异常让代码更优美

    与asp.net 打交道很多年,如今天微软的优秀框架越来越多,其中微软在基于mvc的思想架构,也推出了自己的一套asp.net mvc 框架,如果你亲身体验过它,会情不自禁的说‘漂亮’.回过头来,‘漂 ...

  6. WebApi返回Json格式字符串

    WebApi返回json格式字符串, 在网上能找到好几种方法, 其中有三种普遍的方法, 但是感觉都不怎么好. 先贴一下, 网上给的常用方法吧. 方法一:(改配置法) 找到Global.asax文件,在 ...

  7. Unable to create the selected property page. An error occurred while automatically activating bundle net.sourceforge.pmd

    解决方案: 在命令行到eclipse目录下使用 eclipse.exe -clean

  8. CSS入门常见的问题

    写在前面:本文简单介绍一下css的三大特性:层叠性.继承性.优先级.以及margin,padding,浮动,定位几个知识点.限于水平,不深入探讨,仅作为学习总结. 1,三特性 1)层叠性:同标签同权重 ...

  9. 开源 iOS 项目分类索引大全 - 待整理

    开源 iOS 项目分类索引大全 GitHub 上大概600个开源 iOS 项目的分类和介绍,对于你挑选和使用开源项目应该有帮助 系统基础库 Category/Util sstoolkit 一套Cate ...

  10. Atitit.attilax软件研发与项目管理之道

    Atitit.attilax软件研发与项目管理之道 1. 前言4 2. 鸣谢4 3. Genesis 创世记4 4. 软件发展史4 5. 箴言4 6. 使徒行传 4 7. attilax书 4 8. ...