使用ABP框架踩过的坑系列5
DDD领域驱动开发,实际是为复杂的业务场景而生的,为了让开发人员专注于业务,而操作系统、数据库、网络之类的技术细节,必须要持久透明化:实际就是数据库系统DBMS的ORM抽象,目标就是业务不需要考虑数据是如何存储的,业务是独立于DBMS, 通俗讲业务系统不依赖某个DBMS实现,可以通过配置,灵活动态支持各种DBMS,如MS SQL、MySql、Orcacle等。ABP的目标是DDD, 在持久透明化这块,是用IRepository仓储抽象来做的,具体的DBMS实现的ORM就放在基础架构层Infrastructure里。理想是很美好的,实际还是有些坑的,我在做一个项目,当把MSSQL切换到MySql,还是遇到了问题!
public static class DbContextConfigurer
{
public static void Configure(DbContextOptionsBuilder<DbContext> builder, string connectionString)
{
//builder.UseSqlServer(connectionString); //使用MSSQL
builder
//.UseLoggerFactory(MyLoggerFactory)
.UseMySql(connectionString); //使用MySql
}
public static void Configure(DbContextOptionsBuilder<DbContext> builder, DbConnection connection)
{
//builder.UseSqlServer(connection);
builder.UseMySql(connection);
}
}
用ABP模板生成的项目中,如果使用.netcore和EFcore, 就会有DbContextConfigurer,只要安装了Microsoft.entityframeworkcore.mysql, 就可以使用UseMySql这个扩展方法,
"ConnectionStrings": {
//"Default": "Server=localhost; Database=Db3; Trusted_Connection=True;"
"Default": "Server=localhost;port=3306;database=Db3;uid=root;password=root;character set=utf8;Old Guids=true"
},
appsettings.json 里ConnectionStrings,也使用Mysql连接字符串,然后再PMC(程序包控制台)执行
update-dabase
完成以上步骤,从MSSQL切换到了Mysql, 大功告成!理想是这样的,事实上也大部分可行,但会报一些莫名其妙的错误:约束错误!这些问题,一度让我很沮丧,甚至想放弃mysql, 迫于linux下装MSSQL的恐怖,还是坚持用mysql, 后在baidu的帮助下,找到了原因:Microsoft.entityframeworkcore.mysql 有问题,必须用melo.EntityFrameworkCore.MySql
然后再PMC(程序包控制台)执行
install-package Pomelo.EntityFrameworkCore.MySql
再执行update-dabase, 真的一切都好了,其实在ORM的抽象和实现方面,ABP都比较好的Module, 当家的是Microsoft的EF
Abp.EntityFrameWork.Common //EF的公共部分 Abp.EntityFrameWork //EF Abp.EntityFrameWorkCore //EFCore
还有来自Java阵营的
Abp.NHibernate
还有几个比较流行的,
Abp.Dapper //据说性能是ef几十倍的DapperAbp.MongoDB //nosql,KV和文档数据库Abp.MemoryDb //内存数据库,可用于单元测试,棒棒的
个人还是偏爱EF系列,特别是linux下用EFCore+Mysql, 是最佳组合,经过几个项目的实战,证明是个不错选择,可以放心使用!
ABP有关ORM的抽象机制,主要通过Repostitory和UnitOfWork来做的
namespace Abp.Domain.Repositories
{
/// <summary>
/// This interface is implemented by all repositories to ensure implementation of fixed methods. 说白了就是CRUD得封装
/// </summary>
/// <typeparam name="TEntity">Main Entity type this repository works on</typeparam>
/// <typeparam name="TPrimaryKey">Primary key type of the entity</typeparam>
public interface IRepository<TEntity, TPrimaryKey> : IRepository where TEntity : class, IEntity<TPrimaryKey>
{
#region Select/Get/Query
...#endregion
#region Insert
...#endregion
#region Update
...#endregion
#region Delete
...#endregion
#region Aggregates
...#endregion
}
}
/// <summary>
/// Defines a unit of work.
/// This interface is internally used by ABP. 实际上就是数据库连接和事务的封装
/// Use <see cref="IUnitOfWorkManager.Begin()"/> to start a new unit of work.
/// </summary>
public interface IUnitOfWork : IActiveUnitOfWork, IUnitOfWorkCompleteHandle
{
/// <summary>
/// Unique id of this UOW.
/// </summary>
string Id { get; }
/// <summary>
/// Reference to the outer UOW if exists.
/// </summary>
IUnitOfWork Outer { get; set; }
/// <summary>
/// Begins the unit of work with given options.
/// </summary>
/// <param name="options">Unit of work options</param>
void Begin(UnitOfWorkOptions options);
具体我们在Service中,只要用DI就可以注入了,其实现机理,以EFCore为例
/// <summary>
/// This module is used to implement "Data Access Layer" in EntityFramework. 类似Mybatis的数据访问层,在ABP中叫基础架构
/// </summary>
[DependsOn(typeof(AbpKernelModule))]
public class AbpEntityFrameworkCoreModule : AbpModule
{
。。。private void RegisterGenericRepositoriesAndMatchDbContexes()
{
var dbContextTypes =
_typeFinder.Find(type =>
type.IsPublic &&
!type.IsAbstract &&
type.IsClass &&
typeof(AbpDbContext).IsAssignableFrom(type)
);
if (dbContextTypes.IsNullOrEmpty())
{
Logger.Warn("No class found derived from AbpDbContext.");
return;
}
using (var repositoryRegistrar = IocManager.ResolveAsDisposable<IEfCoreGenericRepositoryRegistrar>())
{
foreach (var dbContextType in dbContextTypes)
{
Logger.Debug("Registering DbContext: " + dbContextType.AssemblyQualifiedName);
repositoryRegistrar.Object.RegisterForDbContext(dbContextType, IocManager);
}
}
。。。
}
}
public class EfCoreGenericRepositoryRegistrar : IEfCoreGenericRepositoryRegistrar, ITransientDependency
{
。。。public void RegisterForDbContext(Type dbContextType, IIocManager iocManager)
{
var autoRepositoryAttr = dbContextType.GetSingleAttributeOrNull<AutoRepositoryTypesAttribute>() ??
EfCoreAutoRepositoryTypes.Default;
foreach (var entityTypeInfo in DbContextHelper.GetEntityTypeInfos(dbContextType))
{
var primaryKeyType = EntityHelper.GetPrimaryKeyType(entityTypeInfo.EntityType);
if (primaryKeyType == typeof(int))
{
var genericRepositoryType = autoRepositoryAttr.RepositoryInterface.MakeGenericType(entityTypeInfo.EntityType);
if (!iocManager.IsRegistered(genericRepositoryType))
{
? autoRepositoryAttr.RepositoryImplementation.MakeGenericType(entityTypeInfo.EntityType)
: autoRepositoryAttr.RepositoryImplementation.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType);
iocManager.Register(
genericRepositoryType,
implType,
DependencyLifeStyle.Transient
);
}
}
var genericRepositoryTypeWithPrimaryKey = autoRepositoryAttr.RepositoryInterfaceWithPrimaryKey.MakeGenericType(entityTypeInfo.EntityType, primaryKeyType);
if (!iocManager.IsRegistered(genericRepositoryTypeWithPrimaryKey))
{
? autoRepositoryAttr.RepositoryImplementationWithPrimaryKey.MakeGenericType(entityTypeInfo.EntityType, primaryKeyType)
: autoRepositoryAttr.RepositoryImplementationWithPrimaryKey.MakeGenericType(entityTypeInfo.DeclaringType, entityTypeInfo.EntityType, primaryKeyType);
iocManager.Register(
genericRepositoryTypeWithPrimaryKey,
implType,
DependencyLifeStyle.Transient
);
}
}
}
}
整个目的就是为了可以注入泛型的IRepostitory<TEntity, TPrimaryKey>,我们的service,就可以愉快的使用了
public IRepository<FoodMaterial, long> FoodMaterialRepository { get; set; } //属性注入
//或
private IRepository<FoodMaterialCategory, long> _categoryRepository;
public FoodMaterialAppService(IRepository<FoodMaterial, long> repository
, IRepository<FoodMaterialCategory, long> categoryRepository)
: base(repository)
{
_categoryRepository = categoryRepository;
} // 构造注入
总结:.net 已经拥抱开源和linux了,曾经的四大金刚LAMP(Linux+Apache+Mysql+Php),如今.net也可以Cover了,跨平台(操作系统、数据库等),是一个上线系统的必须,特别部署到云上,linux+mysql的性价比还是比较高的,可真正要做到跨平台和持久透明,在设计DB时,还是要注意:不要用存储过程,所有逻辑必须在代码里完成,DB只是用来存储的;ABP在这个领域,给了我们OutOfBox开箱即用的很多Module, 可以让我们效率大大提升!
使用ABP框架踩过的坑系列5的更多相关文章
- ABP框架踩过的坑系列6
ABP框架踩过的坑系列6 应是无事.齐侯方才的确到了吴纠庭院https://www.mixcloud.com/ltTFvU888smi8jS/几日行军劳顿其实齐侯本应该睡下了https://www.m ...
- 使用ABP框架踩过的坑系列1
企业级(例如ERP)应用, 一遍一遍的在重复:认证.验证.异常处理.日志.国际化和本地化.数据库连接管理.配置管理. 审计记录等,同时.NET有很多最佳实践:分层.模块化.DDD领域驱动.DI ...
- 使用ABP框架踩过的坑系列4
数据库连接和事务管理,是数据库应用中的最重要概念之一.做过的人,都会头疼:何时Open一个连接?何时Start一个事务?何时Dispose这个连接?... ABP框架试图用一个叫做UnitOfWork ...
- 使用ABP框架踩过的坑系列3
从架构角度来讲,ApplicationService究竟应该如何定位,一种说法是直接对应用例UseCase, 也就是直接对应UI, 这个UI是广义的,不仅仅是浏览器的页面,也包括API调用.还是从我曾 ...
- 使用ABP框架踩过的坑系列2
ABP中有很多惯例,如果使用得当,可以事半功倍,如果使用不当,也会有很大的麻烦,是否适当其实还是要看Need需求 ASP.NET Boilerplate (ABP) is an open source ...
- ABP框架踩坑记录
ABP框架踩坑记录 ASP.NET Boilerplate是一个专用于现代Web应用程序的通用应用程序框架. 它使用了你已经熟悉的工具,并根据它们实现最佳实践. 文章目录 使用MySQL 配置User ...
- Abp框架之执行Update-Database 命令系列错误
废话不多说,直接开门见山.首先的 第一个错误:一般都是,碰到这个问题不要慌,先不要急着去查看sql服务是否开启,首先按F5启动项目,报错之后直接终止项目,然后再执行Update-Database命令 ...
- 谈谈出入React框架踩过的坑
1 在JSX的元素中写入内联样式,例如<div style={"color:blue"}></div> 报错:warning:Style prop valu ...
- 踩过的坑系列之InputStream.read(byte[])方法
项目之前都是好好的,最近现场那边出现一个问题,报错不是合法的json字符串,这个json字符串是通过http请求访问获得的. 通过直接在浏览器上直接访问http这个请求,发现返回的json也是完全正确 ...
随机推荐
- VirtualBox中的虚拟机在Ubuntu 下无法启动之问题解决
我通过重新安装box解决的.发现,box安装,直接apt install有可能会出现虚拟机无法启动的问题. 一.添加VirtualBox的源并安装5.1版本virtualbox官网:https://w ...
- 中文路径读取乱码,json乱码
strPath = 'E:\新建文件夹' #含有中文的路径,使用unicode函数转换. strPath = unicode(strPath , "utf8") 参考:http:/ ...
- 理解数据结构Priority Queue
我们知道Queue是遵循先进先出(First-In-First-Out)模式的,但有些时候需要在Queue中基于优先级处理对象.举个例子,比方说我们有一个每日交易时段生成股票报告的应用程序,需要处理大 ...
- 每天学一点儿HTML5的新标签
sections部分 (http://www.w3.org/TR/html5/sections.html) 标签:article article标签用来表示页面中一段完整的可以自我包含的片段,具有可重 ...
- js this pointer 指针
this JavaScript的函数内部如果调用了this,那么这个this到底指向谁? 答案是,视情况而定! 如果以对象的方法形式调用,比如xiaoming.age(),该函数的this指向被调用的 ...
- maven项目工程目录约定
使用maven创建的工程我们称它为maven工程,maven工程具有一定的目录规范,如下: src/main/java —— 存放项目的.java文件 src/main/resources —— 存放 ...
- Sql优化-必劳记!
0. 尝试在合适的场景下,用 Charindex()函数代替 like,或者全文索引进行 内容搜寻.%like%不走索引,'like%'后百分号可以走索引. 1.调整不良SQL通常可以从以下几点切入: ...
- C#中发送邮件,包含Html代码 CDO.Message
C#代码: /// <summary> /// 发送邮件 /// </summary> /// <param name="context">&l ...
- Apache模块开发
一.简介 Apache HTTP服务器是一个模块化的软件,使管理者可以选择核心中包含的模块以裁剪功能.可以在编译时选择被静态包含进httpd二进制映象的模块,也可以编译成独立于主httpd二进制映象的 ...
- Ubuntu12.04添加环境变量
环境变量分为系统级和用户级. 系统级变量设置环境为/etc/environment和/etc/profile等,不要轻易修改,否则可能造成系统错误. 用户级变量设置路径为-/.bashrc和~/.pr ...