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的更多相关文章

  1. ABP框架踩过的坑系列6

    ABP框架踩过的坑系列6 应是无事.齐侯方才的确到了吴纠庭院https://www.mixcloud.com/ltTFvU888smi8jS/几日行军劳顿其实齐侯本应该睡下了https://www.m ...

  2. 使用ABP框架踩过的坑系列1

        企业级(例如ERP)应用, 一遍一遍的在重复:认证.验证.异常处理.日志.国际化和本地化.数据库连接管理.配置管理. 审计记录等,同时.NET有很多最佳实践:分层.模块化.DDD领域驱动.DI ...

  3. 使用ABP框架踩过的坑系列4

    数据库连接和事务管理,是数据库应用中的最重要概念之一.做过的人,都会头疼:何时Open一个连接?何时Start一个事务?何时Dispose这个连接?... ABP框架试图用一个叫做UnitOfWork ...

  4. 使用ABP框架踩过的坑系列3

    从架构角度来讲,ApplicationService究竟应该如何定位,一种说法是直接对应用例UseCase, 也就是直接对应UI, 这个UI是广义的,不仅仅是浏览器的页面,也包括API调用.还是从我曾 ...

  5. 使用ABP框架踩过的坑系列2

    ABP中有很多惯例,如果使用得当,可以事半功倍,如果使用不当,也会有很大的麻烦,是否适当其实还是要看Need需求 ASP.NET Boilerplate (ABP) is an open source ...

  6. ABP框架踩坑记录

    ABP框架踩坑记录 ASP.NET Boilerplate是一个专用于现代Web应用程序的通用应用程序框架. 它使用了你已经熟悉的工具,并根据它们实现最佳实践. 文章目录 使用MySQL 配置User ...

  7. Abp框架之执行Update-Database 命令系列错误

    废话不多说,直接开门见山.首先的 第一个错误:一般都是,碰到这个问题不要慌,先不要急着去查看sql服务是否开启,首先按F5启动项目,报错之后直接终止项目,然后再执行Update-Database命令 ...

  8. 谈谈出入React框架踩过的坑

    1 在JSX的元素中写入内联样式,例如<div style={"color:blue"}></div> 报错:warning:Style prop valu ...

  9. 踩过的坑系列之InputStream.read(byte[])方法

    项目之前都是好好的,最近现场那边出现一个问题,报错不是合法的json字符串,这个json字符串是通过http请求访问获得的. 通过直接在浏览器上直接访问http这个请求,发现返回的json也是完全正确 ...

随机推荐

  1. zoj1109-Language of FatMouse 【字典树】

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=109 Language of FatMouse Time Limit: 10 S ...

  2. 【Python基础教程第2版】——第二讲:列表和元组

    引言: 什么是数据结构? 数据结果是通过某种方式(例如对元素进行编号)组织在一起的数据元素的集合.Python中最常用的数据结构是序列. Python包含6种内建的序列:列表和元组(最常用:列表可以修 ...

  3. boost x64 lib

    libboost_atomic-vc150-mt-gd-x64-1_66.liblibboost_atomic-vc150-mt-s-x64-1_66.liblibboost_atomic-vc150 ...

  4. iOS - push 或 pop或点击导航栏返回pop指定导航控制器

    以前一直有个很疑惑的问题没有搞清楚 关于ios中 viewcontroller的跳转问题,其中有一种方式是采用navigationController pushViewController 的方法,比 ...

  5. 20-最大k乘积问题

    /*                                             最大k乘积问题        题目内容: 设I是一个n位十进制整数.如果将I划分为k段,则可得到k个整数. ...

  6. LFS(Linux From Scratch)学习

    一.简介 LFS──Linux from Scratch,就是一种从网上直接下载源码,从头编译LINUX的安装方式.它不是发行版,只是一个菜谱,告诉你到哪里去买菜(下载源码),怎么把这些生东西( ra ...

  7. json.dumps错误:'utf8' codec can't decode byte解决方案-乾颐堂

    一次在使用json.dumps()过程中,出现错误提示: ERROR:"UnicodeDecodeError: 'utf8' codec can't decode byte 0xe1 in ...

  8. 都是假的!这位小姐姐 P 的图,认真看你就输了!

    开门见山,先来看张图: 肯定有不少小伙伴用不屑的语气说,嗬!一看就是 P 的! 是的,任谁都能一眼看出来是假的.但你可能想象不到,这张图的原始素材是有多么……支离破碎,熊是动物园里的,小孩是在家门口站 ...

  9. PetaPoco与MySQL

    随便写写的,PetaPoco与MySQL一起使用,在一个工控项目中充分使用节省不少开发时间,经历大半年的努力的项目接近完成,客户不认帐,开始需求合同就是个败笔,技术还是仅能解决技术问题而已! 上图上代 ...

  10. VS2010 MFC 使用GDI+给图片添加汉字

    1.配置GDI+ VS2010自带GDI+,直接使用. (1)首先要添加头文件和库 #pragma comment( lib, "gdiplus.lib" ) #include & ...