ABP官方文档翻译 9.1 EntityFramework集成
EntityFramework集成
ABP可以使用ORM框架,它内置集成EntityFramework。本文档将讲解ABP如何使用EntityFramework。假定你对EntityFramework已经有了初级水平。
Nuget包
在ABP中使用Abp.EntityFramework nuget包扩展了EntityFramework。需要将它添加到工程中。最好在一个单独的程序集(dll)中实现EntityFramework并在此程序集中引用Abp.EntityFramework包。
DbContext
如你所知,为了使用EntityFramework,你需要在应用中定义一个DbContext。一个实例DBContext如下所示:
public class SimpleTaskSystemDbContext : AbpDbContext
{
public virtual IDbSet<Person> People { get; set; }
public virtual IDbSet<Task> Tasks { get; set; } public SimpleTaskSystemDbContext()
: base("Default")
{ } public SimpleTaskSystemDbContext(string nameOrConnectionString)
: base(nameOrConnectionString)
{ } public SimpleTaskSystemDbContext(DbConnection existingConnection)
: base(existingConnection, false)
{ } public SimpleTaskSystemDbContext(DbConnection existingConnection, bool contextOwnsConnection)
: base(existingConnection, contextOwnsConnection)
{ } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); modelBuilder.Entity<Person>().ToTable("StsPeople");
modelBuilder.Entity<Task>().ToTable("StsTasks").HasOptional(t => t.AssignedPerson);
}
}
这是一个正规的DbContext类,除此之外它遵循以下规则:
- 从AbpDbContext集成而不是DbContext。
- 需要有构造函数如上面的示例(构造函数参数命名也需要一样)。说明:
- 默认构造函数传递“Default”到基类作为连接字符串。所以,在web.config/app.config文件中有一个名为“Default”的连接字符串。ABP不使用个这构造函数,但是EF命令行迁移工具和工具命令(如 update-database)使用它。
- 带nameOrConnectiongString参数的构造函数,ABP用来在运行时传递连接名称或字符串。
- 带existingConnection参数的构造函数用于单元测试,ABP不直接使用。
- 带existingConnection和contxtOwnsConnection的构造函数,当使用DbContextEfTransactionStrategy时(参见下面的事务管理部分),ABP用于单数据库多dbcontext的场景来共享同一个连接、事务。
EntityFramework使用常规的方式将类映射到数据库表。除非自定义了功能,你不需要做任何配置。在这个例子中,我们将实体映射到不同的表。Task实体默认映射到Tasks表。但是我们可以改变它映射到StsTasks表。比起使用数据注解,我更喜欢使用流配置。你可以选择自己喜欢的方式。
仓储
仓储用来从高层抽象数据访问。参见仓储文档了解更多。
默认仓储
Abp.EntityFramework为定义在DbContext中的所有实体实现默认仓储。你不必创建仓储类来使用预定义的仓储方法。示例:
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>)并使用预定义方法。
自定义仓储
如果标准的仓储方法不能满足,你可以为你的实体创建自定义仓储类。
应用特定的基础仓储类
ABP提供了一个基础类EfRepositoryBase来实现仓储。为了实现IRepository接口,可以将你的仓储类从这个类集成。但是最好创建自己的基类并扩展EfRepositoryBase。从而,你可以在自己的仓储中添加shared/common方法或重写已经存在的方法。下面是SimpleTaskSystem应用的所有仓储基类的示例:
//Base class for all repositories in my application
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>
where TEntity : class, IEntity<TPrimaryKey>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
} //add common methods for all repositories
} //A shortcut for entities those have integer Id
public class SimpleTaskSystemRepositoryBase<TEntity> : SimpleTaskSystemRepositoryBase<TEntity, int>
where TEntity : class, IEntity<int>
{
public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider)
: base(dbContextProvider)
{
} //do not add any method here, add to the class above (because this class inherits it)
}
注意,我们从EfRepositoryBase<SimpleTaskSystemDbContext,TEntity,TPrimaryKey>继承。这表明ABP在我们的仓储中使用SimpleTaskSystemDbContext。
默认,对于所有给定DbContext(在这个例子中为SimpleTaskDbContext)的仓储都使用EfRepositoryBase实现。你可以在你的DbContext中添加AutoRepository特性来使用自己的仓储基类,如下:
[AutoRepositoryTypes(
typeof(IRepository<>),
typeof(IRepository<,>),
typeof(SimpleTaskSystemEfRepositoryBase<>),
typeof(SimpleTaskSystemEfRepositoryBase<,>)
)]
public class SimpleTaskSystemDbContext : AbpDbContext
{
...
}
自定义仓储示例
为了实现自定义仓储,在你的应用中继承一个以上我们定义的基础仓储类。
假定,我们有一个Task实体,它可以分配给一个Person(实体)并Task有一个State(new,assigned,completed...等等)。我们需要编写一个自定义方法使用一些条件和AssisgnedPerson属性来预获取Tasks的列表。参见下面的示例代码:
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();
}
}
我们首先定义了ITaskRepostory接口并实现了它。GetAll()返回IQueryable<Task>,然后我们可以使用给定的参数添加一些Where过滤器。最后我们调用ToList()来获取Tasks列表。
你也可以在仓储方法中使用Context对象引用你自己的DbContext,然后直接使用Entity Framework APIs。
注意:对于分层应用,在domain/core层定义自定义仓储接口,在EntityFramework工程中实现它们。从而,你可以在任何工程中注入这个接口而不用引用EF。
仓储最佳实践
- 在可能的地方使用默认仓储。即使你有一个实体的自定义仓储(如果你将使用标准的仓储方法),也可以使用默认的仓储。
- 总是为自定义仓储创建仓储基类,如上面定义的那样。
- 在领域层定义自定义仓储的接口,如果你想将EF从你的domain/application中抽象出来,在EntityFramework工程中自定义仓储类。
事务管理
ABP有内置的工作单元系统来管理数据库连接和事务。Entity Framework有不同的事务管理方式。ABP默认使用TransactionScope方式,但是也有DbContext事务API的内置实现。如果你想切换到DbContext事务API,可以在模块的PreInitialize方法中配置它:
Configuration.ReplaceService<IEfTransactionStrategy, DbContextEfTransactionStrategy>(DependencyLifeStyle.Transient);
记住,在代码中添加"using Abp.Configuration.Startup"以便能使用ReplaceService的泛型扩展方法。
另外,如在DbContext部分所描述的那样,你的DbContext需要有构造函数。
数据存储
因为ABP内置集成EntityFramework,那么它就可以使用EntityFramework所支持的数据存储。我们免费的启动模板设计为使用Sql Server,但是你可以修改他们以便使用不同的数据存储。
例如,如果你想使用MySql,请参见这个文档。
ABP官方文档翻译 9.1 EntityFramework集成的更多相关文章
- ABP官方文档翻译 7.2 Hangfire集成
Hangfire集成 介绍 ASP.NET Core集成 ASP.NET MVC 5.x集成 面板授权 介绍 Hangfire是一个综合的后台job管理器.你可以 把它集成到ABP,用来取代默认的后台 ...
- ABP官方文档翻译 9.3 NHibernate集成
NHibernate集成 Nuget包 配置 实体映射 仓储 默认实现 自定义仓储 应用程序特定基础仓储类 ABP可以使用任何ORM框架,它内置集成NHibernate.此文档将讲解ABP如何使用NH ...
- ABP官方文档翻译 8.2 SignalR集成
SignalR集成 介绍 安装 服务器端 客户端 建立连接 內建特征 通知 在线客户端 PascalCase与CamelCase对比 你的SignalR代码 介绍 ABP中的Abp.Web.Signa ...
- ABP官方文档翻译 7.3 Quartz集成
Quartz集成 介绍 安装 创建Jobs 计划安排Jobs 更多 介绍 Quartz是一个全功能的.开源的job计划安排系统,可以用在小的apps也可以用于大型的企业系统.Abp.Quartz包简化 ...
- ABP官方文档翻译 5.4 SwaggerUI集成
SwaggerUI集成 介绍 ASP.NET Core 安装Nuget包 配置 测试 ASP.NET 5.x 安装Nuget包 配置 测试 介绍 在它的网站上:“...使用Swagger可用的API, ...
- ABP官方文档翻译 5.3 OData集成
OData集成 介绍 安装 安装Nuget包 设置模块依赖 配置实体 创建控制器 配置 示例 获取实体列表 Request Response 获取单个实体 Request Response 使用导航属 ...
- ABP官方文档翻译 1.6 OWIN集成
OWIN集成 安装 使用 如果在应用程序里既使用ASP.NET MVC也使用ASP.NET Web API,需要在工程里安装Abp.Owin包. 安装 添加Abp.Owin包到主工程里(一般是web工 ...
- ABP官方文档翻译 10.1 ABP Nuget包
ABP Nuget包 Packages Abp Abp.AspNetCore Abp.Web.Common Abp.Web Abp.Web.Mvc Abp.Web.Api Abp.Web.Api.OD ...
- ABP官方文档翻译 0.0 ABP官方文档翻译目录
一直想学习ABP,但囿于工作比较忙,没有合适的契机,当然最重要的还是自己懒.不知不觉从毕业到参加工作七年了,没留下点儿什么,总感觉很遗憾,所以今天终于卯足劲鼓起勇气开始写博客.有些事能做的很好,但要跟 ...
随机推荐
- HUST 1583 长度单位
1583 - 长度单位 时间限制:1秒 内存限制:128兆 536 次提交 103 次通过 题目描述 我们生活中常用的长度单位有英尺.英寸和厘米,众所周知它们之间的换算关系每英寸等于3厘米,而每英尺等 ...
- BZOJ:4873: [Shoi2017]寿司餐厅
4873: [Shoi2017]寿司餐厅 首先很开心在膜你赛的时候做了出来. 看到数据范围,看到不能dp,看到贡献去重后计算,咦,流? 那就容易了,转最大权闭合子图,每个区间建一个点,取了就一定要取他 ...
- 【Java学习笔记之五】java数组详解
数组 概念 同一种类型数据的集合.其实数组就是一个容器. 数组的好处 可以自动给数组中的元素从0开始编号,方便操作这些元素. 格式1: 元素类型[] 数组名 = new 元素类型[元素个数或数组长度] ...
- Vijos P1116 一元三次方程求解【多解,暴力,二分】
一元三次方程求解 描述 有形如:ax^3+bx^2+cx+d=0 这样的一个一元三次方程.给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之 ...
- 2017ecjtu-summer training #1 UVA 10399
It has been said that a watch that is stopped keeps better time than one that loses 1 second per day ...
- [国嵌攻略][069][Bootm命令移植]
Bootloader作用 1.初始化软硬件 2.启动操作系统 内核分类 1.zImage 不加信息头的内核 2.uImage 加信息头后的内核,用bootm命令来启动 bootm作用 1.检测信息头: ...
- POJ 1797 Heavy Transportation(Dijkstra变形——最长路径最小权值)
题目链接: http://poj.org/problem?id=1797 Background Hugo Heavy is happy. After the breakdown of the Carg ...
- Sublime Text 使用介绍、全套快捷键及插件推荐
开篇:如果说Notepad++是一款不错Code神器,那么Sublime Text应当称得上是神器滴哥.Sublime Text最大的优点就是跨平台,Mac和Windows均可完美使用:其次是强大的插 ...
- ip001
----------- <?phpheader('Content-type:text/html;charset=utf8');// <script type="text/java ...
- NSDateFormatter相关整理
//实例化一个NSDateFormatter对象NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init]; //设定时间格式,这里可 ...