9.1 ABP基础设施层 - 集成Entity Framework

ABP可以与任何ORM框架协同工作,它内置了对EntityFramework的集成支持。本文将介绍如何在ABP中使用EntityFramework。本文假定你已经初步掌握了EntityFramework。

译者注:怎么才算初步掌握了EntityFramework呢?译者认为应当懂得使用Code First模式进行CRUD。

9.1.1 Nuget包

在ABP中要使用EntityFramework作为ORM框架的话,需要到Nuget上下载一个名为Abp.EntityFramework的包。比较好的做法是:新建一个独立的程序集(dll),然后在这个程序集中调用这个包和EntityFramework。

ABP官方提供的模板程序就是这样做的。模板程序的下载方法详见《ABP系列之2、ABP入门教程》

9.1.2 创建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("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);}
}

上面是一个常规的ABP的DbContext,它还需要遵循下列规则:

  • 它派生自 AbpDbContext 而不是DbContext。

  • 如上面示例所示:它应该有构造函数(构造函数的参数名字也应该相同):

    • Default 构造函数传入 “Default” 给基类作为连接字符串。所以,这表示在web.config/app.config文件中有一个名字为 “Default” 的连接字符串。该构造函数不是被ABP使用,它是被迁移工具EF命令行使用的,如:update-database。

    • 在运行时ABP通过构造函数取得 nameOrConnectionString 来传入连接名或连接字符串。

    • 在单元测试的时候使用构造函数来取得 existingConnection,而不是直接由ABP使用。

    • DbContextEfTransactionStrategy 被使用的时候(请查阅事务管理章节),ABP会通过构造函数取得 existingConnection和contextOwnsConnection,并且在单数据库多dbcontext场景下会共享连接和事务。

EntityFramework可以使用约定的方式来映射实体和数据表。除非你想进行自定义映射,否则你甚至不需要做任何配置。在上例中,我们将实体映射到了不同的表中。默认情况下(按照约定优先于配置的原则,会默认采用约定的方式),Task实体会映射到Tasks表,但在这里我们将它映射到了StsTasks表。相比起使用Data Annotation模式来进行自定义映射,我更喜欢使用Fluent API模式。当然,你可以选择你所喜欢的模式,这里并没有特别的限制。

9.1.3 仓储

仓储被用来从更高层抽象数据访问的。详细请看仓储文档。

默认仓储

Abp.EntityFrameworkCore
为所有在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);}
}

IRepository\

自定义仓储

如果你对标准的仓储方法不满意,你可以对你的实体创建自定义仓储。

特定于应用的基础仓储类

ABP提供了一个基础类:EfRepositoryBase 使用它你可以很容易实现仓储类。为了实现 IRepository 接口,你可以使你的仓储类派生自该类。但是最好的方式是创建你自己的基类来扩展 EfRepositoryBase 类。因此,你可以轻松的添加共享/通用方法给你的仓储类。下面是SimpleTaskSystem应用对所有仓储的基类实现示例:

//应用程序中的所有仓储的基类
public class SimpleTaskSystemRepositoryBase<TEntity, TPrimaryKey> : EfRepositoryBase<SimpleTaskSystemDbContext, TEntity, TPrimaryKey>where TEntity : class, IEntity<TPrimaryKey>
{public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider): base(dbContextProvider){}//为所有仓储添加通用方法
}//对于那些有int类型Id的实体的仓储的快速实现方式
public class SimpleTaskSystemRepositoryBase<TEntity> : SimpleTaskSystemRepositoryBase<TEntity, int>where TEntity : class, IEntity<int>
{public SimpleTaskSystemRepositoryBase(IDbContextProvider<SimpleTaskSystemDbContext> dbContextProvider): base(dbContextProvider){}//别在这里添加任何方法,请将方法添加到上面那个类,因为该类继承了上面的泛型类
}

注意:我们的仓储类都是继承自 EfRepositoryBase\

[AutoRepositoryTypes(typeof(IRepository<>),typeof(IRepository<,>),typeof(SimpleTaskSystemEfRepositoryBase<>),typeof(SimpleTaskSystemEfRepositoryBase<,>)
)]
public class SimpleTaskSystemDbContext : AbpDbContext
{...
}
自定义仓储示例

为了实现一个自定义的仓储,你应该使你创建的应用的仓储派生自上面所说的特定于应用的基础仓储类。

假设我们有一个任务实体且任务能够被分配给某个人并且任务有自己的状态(如:new,assigned,completed 等等)。我们可能需要写一个自定义的方法来取得任务列表并且需要使用某些条件来执行数据过滤,如:分配人,任务状态 来过滤。 如下所示:

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 接口然后实现它。GetAll() 方法返回 IQueryable\

Repository 最佳实践

  • 在任何可能的地方使用默认仓储。即使你的实体有自定义仓储,你也能使用默认仓储(如果你使用了标准的仓储方法)。

  • 如同上面所述:对自定义的仓储创建 仓储基类

  • 在领域层中定义自定义仓储接口(.Core 项目是在启动模板),如果你从你的领域层抽象出EF Core, 那么请在 .EntityFramework 项目中实现自定义仓储类。

9.1.4 事务管理

ABP已有内置的工作单元来管理数据库连接和事务。EF有不同的事务管理方法。ABP默认使用 TransactionScope 包裹的方式,对于DbContext事务API也有内置的扩展。如果你想切换到DbContext事务API,你可以在模块的PreInitialize方法中配置它;如下所示:

Configuration.ReplaceService<IEfTransactionStrategy, DbContextEfTransactionStrategy>(DependencyLifeStyle.Transient);

记住引用 using Abp.Configuration.Startup 命名空间,来使用 ReplaceService 扩展方法。

还有,如同上面DbContext章节所描述的一样,你的DbContext 应该有构造函数

9.1.5 数据存储

由于ABP已经内置的集成了EF,它能很好的支持EF的数据存储功能。在启动模板中默认设计是使用Sql Server,但是你也可以修改它来使用其它数据存储。

例如,如果你想使用MySQL,请参考该[文档](9.4ABP基础设施层-集成Entity Framework MySql.md);

ABP官方文档(四十九)【集成EntityFramework】相关推荐

  1. ABP官方文档(四十五)【集成Hangfire】

    7.2 ABP后台服务 - 集成Hangfire 7.2.1 简介 Hangfire是一个综合性的后台作业管理工具.你可以用Hangfire来替换ABP中默认实现的后台作业管理者.你可以对Hangfi ...

  2. ABP官方文档(四十四)【后台作业和后台工人】

    7.1 ABP后台服务 - 后台作业和后台工人 7.1.1 简介 ABP提供了后台作业和后台工人,来执行应用程序中的后台线程的某些任务. 7.1.2 后台作业 由于各种各样的原因,你需要后台作业以队列 ...

  3. ABP官方文档(四十一)【ASP.NET Core】

    6.8 ASP.NET Core 6.8.1 简介 这篇文档是对ABP中集成的ASP.NET Core的描述.ASP.NET 集成是被实现在 Abp.AspNetCore 中. 迁移到ASP.NET ...

  4. ajax访问带token abp,ABP官方文档(三十八)【AJAX API】

    6.6 ABP表现层 - AJAX API 6.6.2.1 AJAX操作问题 现代的应用经常会使用AJAX,尤其是单页应用,几乎是和服务器通信的唯一手段,执行AJAX通常会有以下步骤: 基本上:为了执 ...

  5. ABP官方文档(三十)【动态WebApi层】

    5.2 ABP表现层 - 动态WebApi层 5.2.1 建立动态WebApi控制器 这是一篇关于ASP.NET Web API的文档.如果你对ASP.NET感兴趣,请阅读ASP.NET Core文档 ...

  6. ABP官方文档(四)【启动配置】

    1.4 ABP总体介绍 - 启动配置 在应用启动之前,abp框架提供了模块基本的配置和方法,大家参照下面这个例子就可以了. 译者注: 在看这一节的内容之前,建议大家先下载module-zero这个例子 ...

  7. Nginx官方文档(四十六)【ngx_stream_access_module|ngx_stream_geo_module|ngx_stream_geoip_module】

    ngx_stream_access_module 示例配置 指令 allow deny ngx_stream_access_module 模块(1.9.2)允许对某些客户端地址限制访问. 示例配置 s ...

  8. ABP官方文档(十八)【领域服务】

    3.4 ABP领域层 - 领域服务 3.4.1 简介 领域服务(或者服务,在DDD模式中)是被用来执行领域操作或者业务规则的.Eric Evans 在他的DDD书中这样说过:一个好的Service应该 ...

  9. Nginx官方文档(三十四)【ngx_http_ssl_module】

    ngx_http_ssi_module 示例配置 指令 ssl ssl_buffer_size ssl_certificate ssl_certificate_key ssl_ciphers ssl_ ...

最新文章

  1. charles和Fiddler感觉哪个更好用
  2. 晒一波程序员的工位,你中意哪一款?
  3. BERT中的词向量指南
  4. Windows 8 应用开发 - 本地数据存储
  5. 调用startActivityForResult,onActivityResult无响应的问题
  6. 可能是全网把 ZooKeeper 概念讲的最清楚的一篇文章
  7. 机器学习——人工神经网络之多层神经网络(多层与三层)
  8. 一步步编写操作系统 46 用c语言编写内核3
  9. azure机器学习_如何在Azure机器学习中使用JSON数据
  10. Android MVP开发模式及Retrofit + RxJava封装
  11. 数据标准在数据治理中的意义
  12. 如何处理DDoS***
  13. C#操作Excel数据库方法
  14. matlab向量的模
  15. PHP 计算个人所得税(两种方式)
  16. axure 7.0 license key
  17. windows11家庭版安装hyperv-v
  18. config server高可用的怀疑(非副本集模式)
  19. XTransfer技术专家康康:从普通程序员到架构师的进化之路
  20. MPLS和LDP基本配置

热门文章

  1. WSL2 启用systemd
  2. Carpenter's Complete Guide to the SAS REPORT Procedure
  3. 强制旋转iPhone界面
  4. 较全的OA系统功能需求
  5. 用vue开发一个猫眼电影web app
  6. 每日java笔试五小题 2020-9-23
  7. 简易版GameFramework游戏框架搭建教程(一)前言
  8. python作中国地图背景气泡图_excel怎么制作中国地图背景效果的气泡图?
  9. airdrop无法点_AirDrop无法正常工作? 这是解决方法
  10. 2018山东计算机录取分数,【分数线】2018山东省公费师范生分数线汇总