ABP 基础设施层——集成 Entity Framework
本文翻译自ABP的官方教程《EntityFramework Integration》,地址为:http://aspnetboilerplate.com/Pages/Documents/EntityFramework-Integration
ABP 可以与任何 ORM 框架协同工作,它内置了对 EntityFramework 的集成支持。本文将介绍如何在 ABP 中使用 EntityFramework。本文假定你已经初步掌握了EntityFramework。
译者注:怎么才算初步掌握了 EntityFramework 呢?译者认为应当懂得使用 Code First 模式进行CRUD。
1 Nuget 包
要在 ABP 中使用 EntityFramework 作为 ORM 框架的话,需要到 Nuget 上下载一个名为 Abp.EntityFramework的包。比较好的做法是:新建一个独立的程序集 (dll),然后在这个程序集中调用这个包和 EntityFramework。
2 创建 DbContext(Creating DbContext)
要使用 EntityFramework,首先需要定义一个 DbContext 类。下面是一个DbContex 类的示例:
public class SimpleTaskSystemDbContext : AbpDbContext
{
public virtual IDbSet<Person> People { get; set; } public virtual IDbSet<Task> Tasks { get; set; }
public SimpleTaskSystemDbContext()
: base("MyConnectionStringName")
{ } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Person>().ToTable("StsPeople");
modelBuilder.Entity<Task>().ToTable("StsTasks").HasOptional(t=> t.AssignedPerson);
} }
上面的 SimpleTaskSystemDbContext 本质上是一个 DbContext 类,它派生自 AbpDbContext,而不是 DbContext。AbpDbContext 提供了很多重载的构造函数,如果需要的话,我们可以使用它。EntityFramework 可以使用约定的方式来映射实体和数据表。除非你想进行自定义映射,否则你甚至不需要做任何配置。在上例中,我们将实体映射到了不同的表中。默认情况下(按照约定优先于配置的原则,会默认采用约定的方式),Task 实体会映射到 Tasks 表,但在这里我们将它映射到了 StsTasks 表。相比起使用 Data Annotation 模式来进行自定义映射,我更喜欢使用 Fluent API 模式。当然,你可以选择你所喜欢的模式,这里没有特别的限制。
3 仓储(Repositories)
ABP 提供了一个名为 EfRepositoryBase 的基类,这使得实现仓储变得简单快捷。要实现 IRepository 接口,你只需要从这个基类进行派生即可。但是更好的做法是,自定义一个派生自 EfRepositoryBase 的基类,然后在这个基类中添加一些通用的方法。这样做的好处是,所有派生自这个基类的仓储都继承了这些通用方法。
(1)应用程序专用的仓储基类(Application specific base repository class)
在下面的例子中,我们定义了一个名为 SimpleTaskSystem 仓储基类,这个类是此应用程序所专用的。
// 应用程序中的所有仓储的基类
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSyst emDbContext> dbContextProvider)
: base(dbContextProvider)
{ } //添加仓储基类的通用方法 } public class SimpleTaskSystemRepositoryBase<TEntity> : SimpleTaskSystemRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSyst emDbContext> dbContextProvider)
: base(dbContextProvider)
{ } // 不 要 在 这 里 添 加 任 何 通 用 方 法 ,通 用 方 法 应 当 被添加到 上 面 的 基 类 中(MyRepositoryBase<TEntity, TPrimaryKey>) }
需 要 注 意 的 是 , 我 们 继 承 了 基 类EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>。这相当于做了一个声明,它会让 ABP 在仓储中调用 SimpleTaskSystemDbContext。
(2)仓储实现(Implementing a repository)
如果你只想使用预定义的仓储方法的话,你甚至不需要为实体创建仓储类。如下所示:
public class PersonAppService : IPersonAppService
{
private readonly IRepository<Person> _personRepository; public PersonAppService(IRepository<Person> personRepository)
{
_personRepository = personRepository;
} public void CreatePerson(CreatePersonInput input)
{
person = new Person { Name = input.Name, EmailAddress = input.EmailAddress };
_personRepository.Insert(person);
}
}
PersonAppService类采用构造函数注入的方式注入了一个IRepository<Person>对象,然后调用了预定义的 Insert 方法。采用这种方式,你可以方便地注入IRepository<TEntity> (或者 IRepository<TEntity, TPrimaryKey>)对象,然后使用预定义的方法。查看仓储文档以获得预定义方法的列表。
(3)自定义仓储(Custom repositories)
要实现自定义仓储,只要从上面所创建的应用程序专用的仓储基类(SimpleTaskSystemRepositoryBase)派生即可。
假定我们有一个名为 Task 的实体,它可以被赋予 Person 实体。Task 有一个状态属性(值为新建、已分配、已完成等)。我们需要编写一个自定义方法,这个方法能根据某些条件获取 Task 列表,并且使得 Task 的 AssisgnedPerson 属性可以在一次数据库查询中被加载(使用 EntityFramework 的贪婪加载方法 Include)。如下所示:
public interface ITaskRepository : IRepository<Task, long>
{
List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state);
} public class TaskRepository : SimpleTaskSystemRepositoryBase<Task, long>, ITaskRepository
{
public TaskRepository(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
} public List<Task> GetAllWithPeople(int? assignedPersonId, TaskState? state)
{
var query = GetAll();
if (assignedPersonId.HasValue)
{
query = query.Where(task => task.AssignedPerson.Id == assignedPersonId.Value);
}
if (state.HasValue)
{
query = query.Where(task => task.State == state);
}
return query
.OrderByDescending(task => task.CreationTime)
.Include(task => task.AssignedPerson)
.ToList();
}
}
我们首先定义了一个名为 ITaskRepository 的接口,紧接着定义了一个名为 TaskRepository 的类来实现它。预定义方法 GetAll()返回了一个 IQueryable<Task> 对象,接着我们将参数放入到 Where 筛选器中,最后调用 ToList()来获得一个 Task 列表。此外,我们可以通过调用 base.Context 属性来获得一个 DbContext 对象,这样一来,你就可以直接使用 Entity Framework 的所有功能。
仓储类应当在构造函数中获取IDbContextProvider对象。通过这种方式,在单元测试的时候,我们可以很容易地注入一个虚拟的 DbContext Provider 对象;而在运行的时候,ABP 会根据配置注入相应的 DbContext Provider 对象。
ABP 基础设施层——集成 Entity Framework的更多相关文章
- ABP 基础设施层——集成 NHibernate
本文翻译自ABP的官方教程<NHibernate Integration>,地址为:http://aspnetboilerplate.com/Pages/Documents/NHibern ...
- 集成 Entity Framework
ABP 基础设施层——集成 Entity Framework 本文翻译自ABP的官方教程<EntityFramework Integration>,地址为:http://aspnetboi ...
- UWP开发之ORM实践:如何使用Entity Framework Core做SQLite数据持久层?
选择SQLite的理由 在做UWP开发的时候我们首选的本地数据库一般都是Sqlite,我以前也不知道为啥?后来仔细研究了一下也是有原因的: 1,微软做的UWP应用大部分也是用Sqlite.或者说是微软 ...
- Asp.Net MVC 模型(使用Entity Framework创建模型类) - Part.1
这篇教程的目的是解释在创建ASP.NET MVC应用程序时,如何使用Microsoft Entity Framework来创建数据访问类.这篇教程假设你事先对Microsoft Entity Fram ...
- Asp.Net MVC 模型(使用Entity Framework创建模型类)
这篇教程的目的是解释在创建ASP.NET MVC应用程序时,如何使用Microsoft Entity Framework来创建数据访问类.这篇教程假设你事先对Microsoft Entity Fram ...
- ABP框架系列之三:(Entity Framework Integration-实体框架集成)
ASP.NET Boilerplate can work with any O/RM framework. It has built-in integration with EntityFramewo ...
- ABP 教程文档 1-1 手把手引进门之 ASP.NET Core & Entity Framework Core(官方教程翻译版 版本3.2.5)
本文是ABP官方文档翻译版,翻译基于 3.2.5 版本 官方文档分四部分 一. 教程文档 二.ABP 框架 三.zero 模块 四.其他(中文翻译资源) 本篇是第一部分的第一篇. 第一部分分三篇 1- ...
- ABP官方文档翻译 9.2 Entity Framework Core
Entity Framework Core 介绍 DbContext 配置 在Startup类中 在模块PreInitialize方法中 仓储 默认仓储 自定义仓储 应用程序特定基础仓储类 自定义仓储 ...
- ABP框架系列之二:(Entity Framework Core-实体核心框架)
Introduction(介绍) Abp.EntityFrameworkCore nuget package is used to integrate to Entity Framework (EF) ...
随机推荐
- Electron Browser加载iframe(webview src属性)
browser或者webcontents 的高度与宽度比例对webview中src的页面结构也是有一定影响的
- Mysql两个time类型计算时间相减
round((UNIX_TIMESTAMP(finishtime)-UNIX_TIMESTAMP(starttime))/60) 得到的时间是分钟数
- XX-net 部署网络
https://github.com/XX-net/XX-Net/wiki/%E4%BD%BF%E7%94%A8Chrome%E6%B5%8F%E8%A7%88%E5%99%A8 主要步骤有三步:安装 ...
- Excel Sheet Column Title (STRING - TYPE CONVERTION)
QUESTION Given a positive integer, return its corresponding column title as appear in an Excel sheet ...
- mongo嗅探器mongosniff
mongo嗅探器 在更高版本被mongoreplay取代. 安装: 在Ubuntu直接apt-get install mongodb即包含有. 使用方法 直接--help查看使用方法,一般使用: mo ...
- TZOJ 5279 马拉松比赛(广搜)
描述 有一块矩形的海域,其中有陆地也有海洋,这块海域是CSUFT_ACM集训队的训练基地,这一天,昌神说要集训队的队员不能总是训练,于是昌神提出了中南林ACM集训队第一场环陆马拉松比赛,顾名思义就是围 ...
- Course Schedule课程表12(用Topological Sorting)
[抄题]: 现在你总共有 n 门课需要选,记为 0 到 n - 1.一些课程在修之前需要先修另外的一些课程,比如要学习课程 0 你需要先学习课程 1 ,表示为[0,1]给定n门课以及他们的先决条件,判 ...
- 解决python中csv文件中文写入问题
一.前言 一般来说,为了方便,使用python的时候都会使用csv模块去写数据到csv文件,但是写入中文的时候,经常会报错: UnicodeEncodeError: 'ascii' codec can ...
- 21-js 实现评论时间格式转化
js里面要用可以用伊尔表达式,循环是用js: document.getElementById("${pj.pltime }").innerHTML = dateToGMT(&quo ...
- php 使用html5 XHR2 上传文件 进度显示
思路:只要我们知道上传文件的总大小,还有上传过程中上传文件的大小,那么就可以实现进度显示了. 在html5中,XMLHttpRequest对象,传送数据的时候,progress事件用来返回进度信息. ...