共计 6045 个字符,预计需要花费 16 分钟才能阅读完成。
ABP 框架实战系列(一)- 长久层介绍篇
-
ABP 框架实战系列(一)- 长久层介绍篇
- 数据长久化
- 数据长久层
- ORM
- ABP 框架的 Entity FrameWork Core
- ABP 的仓储
- 仓储的注意事项
- 博主 GitHub 地址
- 关注公众号留下您的困惑或见解
数据长久化
在开始长久层的介绍之前,咱们先引入一个根底概念:长久化
广义的了解:“长久化”仅仅指把域对象永恒保留到数据库中;狭义的了解,“长久化”包含和数据库相干的各种操作 (长久化就是将有用的数据以某种技术保存起来, 未来能够再次取出来利用, 数据库技术, 将内存数据一文件的模式保留在永恒介质中(磁盘等) 都是长久化的意思。
然而仅仅的长久化会使我的项目不可保护或者前期保护不利,简略的保留性能曾经齐全满足不了当初软件开发的模块性、可维护性、
扩展性、分层性准则,所以就须要一种技术框架,将业务层和数据库之间保留的操作做到可维护性、扩展性、分层性,于是就呈现“长久层”的概念
数据长久层
长久层:设计指标是为整个我的项目提供一个连接高下层、对立、平安和并发的数据长久机制,实现对各种数据库进行长久化的编程工作,并为零碎业务逻辑提供服务。数据长久层提供了数据拜访办法,可能使程序员防止手动编写程序拜访数据长久层,使其专一于业务逻辑的开发,并且可能在不同的我的项目中重用映射框架,大大简化了数据增删改查等性能的开发过程,同时又不丢失多层构造的人造劣势,具备可伸缩性和可扩展性
ORM
ORM 数据长久层的一种子实现,它通过将映射的机制,把数据库中的一条记录当做程序的一个类解决,这样在 CURD 的解决上,真正实现了面向对象开发,也将软件的前期保护周期大大缩短
市面上 .Net Core ORM 工具多如牛毛,就列举如下四种常见框架,应用形式大同小异,此次链上一篇很不错的 EF Core 的入门教程:
EntityFrameWork Core(举荐关注该公众号,干货满满)
[FreeSql]
[Nhibernate-core]
[MyBatis]
ORM 优缺点
-
长处
- ORM 最大的劣势,暗藏了数据拜访细节,“关闭”的通用数据库交互,ORM 的外围。他使得咱们的通用数据库交互变得简单易行,并且齐全不必思考该死的 SQL 语句。疾速开发,由此而来。
- ORM 使咱们结构固化数据结构变得简单易行。在 ORM 年表的史前时代,咱们须要将咱们的对象模型转化为一条一条的 SQL 语句,通过直连或是 DB helper 在关系数据库结构咱们的数据库体系。而当初,基本上所有的 ORM 框架都提供了通过对象模型结构关系数据库构造的性能。
-
毛病
- 对于简单查问,ORM 依然力不从心。尽管能够实现,然而不值的。视图能够解决大部分 calculated column,case,group,having,order by, exists
ABP 框架的 Entity FrameWork Core
DbContext
<font color=Violet>EF 外围须要定义来自 DbContext 类。在 ABP,咱们应该从 abpdbcontext 取得,如下所示 </font>
public class MyDbContext : AbpDbContext | |
{public DbSet<Product> Products { get; set;} | |
public MyDbContext(DbContextOptions<MyDbContext> options) | |
: base(options) | |
{}} |
<font color=violet> 构造函数必须失去 DbContextOptions<T> 如下面所示. 参数名称必须是选项。无奈扭转它,因为 ABP 将它作为匿名对象参数提供。</font>
Configuration(配置数据库连贯字符串)
ABP Module Zero 中,将门路配置在 appsettings.json 文件中 配置格局根本如下
"ConnectionStrings": {"Default": "Data Source = 10.28.253.2;Initial Catalog = EventCloudDb;User Id = sa;Password = Ecsgui123;"}
而对配置文件的加载、以及 DbContext 的注册是通过如下代码实现的(ABP 默认生成)
代码中,EFModule 继承自 ABPModule,表名 EF 这个模块,是一个可插拔的模块,该模块下有三个初始化函数 PreInitialize(预初始化)、Initialize(初始化)、PostInitialize(StartUp 实现之后执行)。
其中,PreInitilize 办法中,蕴含 ABP 框架下对模块中的 AbpEFCore 模块的注册。
[DependsOn(typeof(UniversalCoreModule), | |
typeof(AbpZeroCoreEntityFrameworkCoreModule))] | |
public class UniversalEntityFrameworkModule : AbpModule | |
{ | |
/* Used it tests to skip dbcontext registration, in order to use in-memory database of EF Core */ | |
public bool SkipDbContextRegistration {get; set;} | |
public bool SkipDbSeed {get; set;} | |
public override void PreInitialize() | |
{if (!SkipDbContextRegistration) | |
{Configuration.Modules.AbpEfCore().AddDbContext<UniversalDbContext>(options => | |
{if (options.ExistingConnection != null) | |
{UniversalDbContextConfigurer.Configure(options.DbContextOptions, options.ExistingConnection); | |
} | |
else | |
{UniversalDbContextConfigurer.Configure(options.DbContextOptions, options.ConnectionString); | |
} | |
}); | |
} | |
} | |
public override void Initialize() | |
{IocManager.RegisterAssemblyByConvention(typeof(UniversalEntityFrameworkModule).GetAssembly()); | |
} | |
public override void PostInitialize() | |
{if (!SkipDbSeed) | |
{SeedHelper.SeedHostDb(IocManager); | |
} | |
} | |
} |
在相熟了上述 DbContext 加载配置的过程后,咱们就绝对应的会来到创立 DbContext 局部,这部分内容,ABP 模板在 UniversalDbContextFactory 中,实现了对象 DbContext 的创立
1、创立 DbContextOptionBuilder 创立
2、加载配置文件信息到内存
3、初始化 Builder 信息
4、new 一个新的 DbContext 对象
public class Git_ECSGUI_UniversalDbContextFactory : IDesignTimeDbContextFactory<Git_ECSGUI_UniversalDbContext> | |
{public Git_ECSGUI_UniversalDbContext CreateDbContext(string[] args) | |
{var builder = new DbContextOptionsBuilder<Git_ECSGUI_UniversalDbContext>(); | |
var configuration = AppConfigurations.Get(WebContentDirectoryFinder.CalculateContentRootFolder()); | |
Git_ECSGUI_UniversalDbContextConfigurer.Configure(builder, configuration.GetConnectionString(Git_ECSGUI_UniversalConsts.ConnectionStringName)); | |
return new Git_ECSGUI_UniversalDbContext(builder.Options); | |
} | |
} |
ABP 的仓储
讲完 EF Core 中的 DbContext 在 ABP 中的创立过程,咱们将眼帘转到 Repositories(仓库)中过去,他是畛域层和长久之间的桥梁,存储库用于从高层形象数据拜访。
在 ABP 框架中畛域和长久化层之间的媒介,应用一种相似汇合的接口来拜访实体,每个实体(或者聚合根)应用给一个拆散的仓库
默认仓储
在 ABP 里,一个仓储类实现 IRepository<TEntity,TPrimaryKey> 接口。ABP 默认地为每个实体类型主动创立一个默认仓储。你能够间接注入 IRepository<TEntity>(或 IRepository<TEntity,TPrimaryKey>)。一个应用服务应用仓储把一个实体插入数据库的例子:PersonService 结构器注入 IRepository<Person> 并应用 Insert 办法。
public class PersonService : IPersonService | |
{ | |
private readonly IRepository<Person> _personRepository; | |
public PersonService(IRepository<Person> personRepository) | |
{_personRepository = personRepository;} | |
public void CreatePerson(CreatePersonInput input) | |
{person = new Person { Name = input.Name, EmailAddress = input.EmailAddress}; | |
_personRepository.Insert(person); | |
} | |
} |
自定义仓储
只有当实体须要创立一个自定义的仓储办法时,才须要你创立一个仓储类。
public abstract class Git_ECSGUI_UniversalRepositoryBase<TEntity, TPrimaryKey> : EfCoreRepositoryBase<Git_ECSGUI_UniversalDbContext, TEntity, TPrimaryKey> | |
where TEntity : class, IEntity<TPrimaryKey> | |
{protected Git_ECSGUI_UniversalRepositoryBase(IDbContextProvider<Git_ECSGUI_UniversalDbContext> dbContextProvider) | |
: base(dbContextProvider) | |
{ } | |
// Add your common methods for all repositories | |
} | |
/// <summary> | |
/// Base class for custom repositories of the application. | |
/// This is a shortcut of <see cref="Git_ECSGUI_UniversalRepositoryBase{TEntity,TPrimaryKey}"/> for <see cref="int"/> primary key. | |
/// </summary> | |
/// <typeparam name="TEntity">Entity type</typeparam> | |
public abstract class Git_ECSGUI_UniversalRepositoryBase<TEntity> : Git_ECSGUI_UniversalRepositoryBase<TEntity, int>, IRepository<TEntity> | |
where TEntity : class, IEntity<int> | |
{protected Git_ECSGUI_UniversalRepositoryBase(IDbContextProvider<Git_ECSGUI_UniversalDbContext> dbContextProvider) | |
: base(dbContextProvider) | |
{ } | |
// Do not add any method here, add to the class above (since this inherits it)!!! | |
} |
要实现自定义存储库,只需从下面创立的应用程序特定的根底存储库类中取得。
public interface IUniversalTaskRepository : IRepository<Task> | |
{List<Task> GetTaskByAssignedPersonId(long taskId); | |
} | |
public UniversalTaskRepository:Git_ECSGUI_UniversalRepositoryBase, IUniversalTaskRepository | |
{public UniversalTaskRepository(IDbContextProvider<Git_ECSGUI_UniversalDbContext> dbContextProvider) : base(dbContextProvider) | |
{ } | |
/// <summary> | |
/// 获取某个用户调配了哪些工作 | |
/// </summary> | |
/// <param name="personId"> 用户 Id</param> | |
/// <returns> 工作列表 </returns> | |
public List<Task> GetUniversalTaskId(long taskId) | |
{var query = GetAll(); | |
if (taskId > 0) | |
{query = query.Where(t => t.taskid == taskId); | |
} | |
return query.ToList();} | |
} |
仓储的注意事项
- 仓储办法中,ABP 主动进行数据库连贯的开启和敞开。
- 仓储办法被调用时,数据库连贯主动开启且启动事务。
- 当仓储办法调用另外一个仓储的办法,它们实际上共享的是同一个数据库连贯和事务。
- 仓储对象都是暂时性的,因为 IRepository 接口默认继承自 ITransientDependency 接口。所以,仓储对象只有在须要注入的时候,才会由 Ioc 容器主动创立新实例。
-
默认的泛型仓储能满足咱们大部分的需要。只有在不满足的状况下,才创立定制化的仓储。
博主 GitHub 地址
https://github.com/yuyue5945
关注公众号留下您的困惑或见解