博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用ABP框架踩过的坑系列5
阅读量:5939 次
发布时间:2019-06-19

本文共 7737 字,大约阅读时间需要 25 分钟。

    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
builder, string connectionString) { //builder.UseSqlServer(connectionString); //使用MSSQL builder //.UseLoggerFactory(MyLoggerFactory) .UseMySql(connectionString); //使用MySql } public static void Configure(DbContextOptionsBuilder
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  //EFAbp.EntityFrameWorkCore //EFCore

还有来自Java阵营的

Abp.NHibernate

还有几个比较流行的,

Abp.Dapper //据说性能是ef几十倍的Dapper Abp.MongoDB //nosql,KV和文档数据库 Abp.MemoryDb //内存数据库,可用于单元测试,棒棒的

个人还是偏爱EF系列,特别是linux下用EFCore+Mysql, 是最佳组合,经过几个项目的实战,证明是个不错选择,可以放心使用!

ABP有关ORM的抽象机制,主要通过Repostitory和UnitOfWork来做的

namespace Abp.Domain.Repositories{    ///     /// This interface is implemented by all repositories to ensure implementation of fixed methods. 说白了就是CRUD得封装    ///     /// 
Main Entity type this repository works on
///
Primary key type of the entity
public interface IRepository
: IRepository where TEntity : class, IEntity
{ #region Select/Get/Query ...#endregion #region Insert ...#endregion #region Update ...#endregion #region Delete ...#endregion #region Aggregates ...#endregion }}
///     /// Defines a unit of work.    /// This interface is internally used by ABP. 实际上就是数据库连接和事务的封装    /// Use 
to start a new unit of work. ///
public interface IUnitOfWork : IActiveUnitOfWork, IUnitOfWorkCompleteHandle { /// /// Unique id of this UOW. /// string Id { get; } /// /// Reference to the outer UOW if exists. /// IUnitOfWork Outer { get; set; } /// /// Begins the unit of work with given options. /// /// Unit of work options void Begin(UnitOfWorkOptions options);

具体我们在Service中,只要用DI就可以注入了,其实现机理,以EFCore为例

///     /// This module is used to implement "Data Access Layer" in EntityFramework. 类似Mybatis的数据访问层,在ABP中叫基础架构    ///     [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
()) { 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
() ?? 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)) { var implType = autoRepositoryAttr.RepositoryImplementation.GetGenericArguments().Length == 1 ? 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)) { var implType = autoRepositoryAttr.RepositoryImplementationWithPrimaryKey.GetGenericArguments().Length == 2 ? 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
FoodMaterialRepository { get; set; } //属性注入//或private IRepository
_categoryRepository; public FoodMaterialAppService(IRepository
repository , IRepository
categoryRepository) : base(repository) { _categoryRepository = categoryRepository; } // 构造注入

 总结:.net 已经拥抱开源和linux了,曾经的四大金刚LAMP(Linux+Apache+Mysql+Php),如今.net也可以Cover了,跨平台(操作系统、数据库等),是一个上线系统的必须,特别部署到云上,linux+mysql的性价比还是比较高的,可真正要做到跨平台和持久透明,在设计DB时,还是要注意:不要用存储过程,所有逻辑必须在代码里完成,DB只是用来存储的;ABP在这个领域,给了我们OutOfBox开箱即用的很多Module, 可以让我们效率大大提升!

转载于:https://www.cnblogs.com/szdlsoft/p/9186284.html

你可能感兴趣的文章
python写入excel(xlswriter)--生成图表
查看>>
Sublime Text 2 和 Verilog HDL
查看>>
NetworkStream.write只能使用一次,后面再使用无效
查看>>
Android Studio离线打包5+SDK
查看>>
oracle进行字符串拆分并组成数组
查看>>
100多个基础常用JS函数和语法集合大全
查看>>
Java8 lambda表达式10个示例
查看>>
innerHTML outerHTML innerText
查看>>
kafka安装教程
查看>>
go语言基础
查看>>
LINQ to SQL活学活用(1):这要打破旧观念
查看>>
Spring boot 嵌入的tomcat不能启动: Unregistering JMX-exposed beans on shutdown
查看>>
【Windows】字符串处理
查看>>
Spring(十八):Spring AOP(二):通知(前置、后置、返回、异常、环绕)
查看>>
CentOS使用chkconfig增加开机服务提示service xxx does not support chkconfig的问题解决
查看>>
微服务+:服务契约治理
查看>>
save
查看>>
Android DrawLayout + ListView 的使用(一)
查看>>
clear session on close of browser jsp
查看>>
asp.net mvc Post上传文件大小限制 (转载)
查看>>