温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何在Asp.Net项目中使用ABP Dapper

发布时间:2021-03-11 15:17:20 来源:亿速云 阅读:224 作者:Leah 栏目:开发技术

如何在Asp.Net项目中使用ABP Dapper?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

一 安装包依赖

  这个不做过多的解释,通过Nuget 包管理器或者通过程序包管理控制台来添加Abp.Dapper的引用,在我们实际的项目中整个类库的结构如下图所示,包含Dapper和EntityFrameworkCore两种方案。

如何在Asp.Net项目中使用ABP Dapper

  二 添加DependsOn属性标签

  后面我们就需要在我们当前类库项目中唯一的SalesDataModule中来做一些初始化和添加DependsOn标签的操作了。

[DependsOn(typeof(AbpZeroCoreEntityFrameworkCoreModule))]
    [DependsOn(typeof(AbpDapperModule))]
    public class SalesDataModule : AbpModule {
        public override void Initialize() {         
            IocManager.RegisterAssemblyByConvention(typeof(SalesDataModule).GetAssembly());
            DapperExtensions.DapperExtensions.SetMappingAssemblies(new List<Assembly> { typeof(SalesDataModule).GetAssembly() });
        }
    }

  这里我们应该了解为什么要添加依赖关系?这个我们当前的SalesDataModule会依赖于AbpDapperModule和AbpZeroCoreEntityFrameworkCoreModule,确立了这样的依赖关系后,在ABP框架中就会将当前Module所依赖的其它Module放到List<AbpModule>的前面,这样通过这样对的层层依赖关系进行拓扑排序就能够保证被依赖的AbpModule一定先进行初始化操作,这样就能够避免引用关系的错误,从而导致代码逻辑的错误,具体说来:如果A 依赖于B,B依赖于C,那么这三个模块之间的排序为C B A,这样在整个Module系统初始化的时候,会先执行Module C的PreIntialize()、Initialize()、PostInitialize()方法,我们看看ABP中的源码。

public virtual void StartModules()
      {
          var sortedModules = _modules.GetSortedModuleListByDependency();
          sortedModules.ForEach(module => module.Instance.PreInitialize());
          sortedModules.ForEach(module => module.Instance.Initialize());
          sortedModules.ForEach(module => module.Instance.PostInitialize());
      }

  这个里面sortedModules就是通过这种依赖关系进行拓扑排序的,然后依次这行每个模块中的这几个方法进行一些初始化的操作。

  三 Entity to Table Mapping

  这个按照官方的解释就是在建立Entity和数据库实体之间的关系,这个类似于在Domain层实体上面添加【Table】标签(个人理解),在这个里面我们还能添加一些其它特性,比如Ignore掉一些导航属性等等......

public sealed class VehicleOrderPlanMapper : ClassMapper<VehicleOrderPlan> {
    public VehicleOrderPlanMapper() {
        Table("VehicleOrderPlan");
        Map(x => x.Branch).Ignore();
        AutoMap();
    }
}

  四 应用

  这个部分就结合具体的项目来谈一谈一些细节方面的东西,我们先来看看具体的代码。

public class VehicleOrderPlanDapperRepository : DcsDapperRepositoryBase<VehicleOrderPlan>, IVehicleOrderPlanDapperRepository {
        public VehicleOrderPlanDapperRepository(IActiveTransactionProvider activeTransactionProvider) : base(activeTransactionProvider) {
        }
 
        public IEnumerable<WeeklyOrderPlanSummary> GetWeeklyOrderPlanSummary(int? yearOfPlan, int? weekOfPlan, string provinceName,
            [CanBeNull]VehicleOrderPlanType[] planType, string marketName, PageRequest page) {
            var sqlParam = new StringBuilder()
                .AppendIf(yearOfPlan.HasValue, $" AND p.YearOfPlan = :{nameof(yearOfPlan)}")
                .AppendIf(weekOfPlan.HasValue, $" AND p.WeekOfPlan = :{nameof(weekOfPlan)}")
                .AppendIf(!provinceName.IsNullOrWhiteSpace(), $@" AND EXISTS ( SELECT 1
    FROM Company C WHERE c.Id = p.DealerId AND c.Status <> {(int)MasterDataStatus.作废}
        AND c.ProvinceName like '%' || :{nameof(provinceName)} || '%')");
 
            var planTypes = new[] {
                VehicleOrderPlanType.周度计划,
                VehicleOrderPlanType.小品种计划,
                VehicleOrderPlanType.移库计划
            };
            if (planType != null && planType.Length > 0)
                planTypes = planTypes.Intersect(planType).ToArray();
 
            var departmentParam = string.Empty;
            if (!marketName.IsNullOrWhiteSpace())
                departmentParam = $" AND (m.Name LIKE '%' || :{nameof(marketName)} || '%')";
 
            var sql = $@"
SELECT p.YearOfPlan, p.WeekOfPlan, TRUNC(p.CreateTime) AS CreateTime, TRUNC(p.StartTime) AS StartTime, TRUNC(p.EndTime) AS EndTime,
       pd.ProductCode, pd.ProductName, pd.ProductType, pd.ProductCategoryCode AS VehicleModelCode, pd.ProductCategoryName AS VehicleModelName,
       Sum(pd.PlannedQuantity) AS PlannedQuantity, Sum(pd.FirstPlannedQuantity) AS FirstPlannedQuantity,
       Sum(pd.QuantityOfAssessment) AS QuantityOfAssessment, Sum(pd.ConfirmedQuantity) AS ConfirmedQuantity
FROM VehicleOrderPlan p
CROSS JOIN VehicleOrderPlanDetail pd
WHERE (p.Status <> {(int)VehicleOrderPlanStatus.作废} AND p.Type in {planTypes.ToSqlInParam()} {sqlParam} AND EXISTS (
    SELECT 1
    FROM DealerMarketDptRelation dm
    WHERE (((dm.BranchId = p.BranchId) AND (dm.DealerId = p.DealerId)) AND (dm.Status = {(int)BaseDataStatus.有效})) AND EXISTS (
        SELECT 1
        FROM MarketingDepartment m
        WHERE ((m.BranchCode = {SunlightConsts.DEFAULT_BRANCH_QRSALESLTD}) AND (m.Status = {(int)BaseDataStatus.有效})) {departmentParam}
            AND (m.Id = dm.MarketId)))) AND (p.Id = pd.VehicleOrderPlanId)
GROUP BY p.YearOfPlan, p.WeekOfPlan, TRUNC(p.CreateTime), TRUNC(p.StartTime), TRUNC(p.EndTime), pd.ProductCode,
         pd.ProductName, pd.ProductType, pd.ProductCategoryCode, pd.ProductCategoryName";
 
            return QueryPaged<WeeklyOrderPlanSummary>(sql, page, new {
                yearOfPlan,
                weekOfPlan,
                provinceName,
                marketName
            });
        }
    }

  这段代码主要是通过具体传入的参数计划年、计划周、省份......等参数到数据库中查询相关的记录,这里我们先看看基类DcsDapperRepositoryBase<VehicleOrderPlan>里面做了些什么?

public class DcsDapperRepositoryBase<TEntity> : DapperEfRepositoryBase<DcsDbContext, TEntity>
        where TEntity : class, IEntity<int> {
        public DcsDapperRepositoryBase(IActiveTransactionProvider activeTransactionProvider) : base(activeTransactionProvider) {
        }
 
        /// <summary>
        /// 以分页的形式查询数据
        /// </summary>
        /// <typeparam name="TValueObject"></typeparam>
        /// <param name="sql"></param>
        /// <param name="pageRequest"></param>
        /// <param name="parameters">参数的匿名对象</param>
        /// <returns></returns>
        protected IEnumerable<TValueObject> QueryPaged<TValueObject>(string sql, PageRequest pageRequest, object parameters = null)
            where TValueObject : ValueObjectBase {
            var orderCondition = (string.IsNullOrWhiteSpace(pageRequest.Ordering) ? string.Empty : "ORDER BY " + pageRequest.Ordering);
            orderCondition.SqlInjectionInspect();
            var pagedSql = $@"WITH ""_data"" AS ({sql}),
     ""_count"" AS (SELECT COUNT(0) AS OverallCount FROM ""_data"")
SELECT *
FROM (SELECT A.*, ROWNUM AS ""RowNum""
      FROM (SELECT * FROM ""_data""
            {orderCondition}) A
      WHERE ROWNUM <= {pageRequest.PageSize * (pageRequest.PageIndex + 1)}) B,
     ""_count""
WHERE ""RowNum"" > {pageRequest.PageSize * pageRequest.PageIndex}";
            return Query<TValueObject>(pagedSql, parameters);
        }
    }

  在这个基类中我们继承了ABP中的基类DapperEfRepositoryBase<DcsDbContext, TEntity>,这个泛型基类第一个参数就是我们项目中的具体DbContext,第二个参数就是我们具体定义的实体,这个实体是主键为Int的自增长类型。这里面由于查询的数据非常多,所以我们这里实际上返回的是分页的第一页的结果集,这里还有一个重要的知识就是,为了防止sql注入,这里sql中的参数都采用参数的匿名对象,而不是直接进行拼接,这个是防止SQL注入的时候最常见的方式。通过这个具体的例子你应该知道怎样在ABP Dapper中使用匿名参数对象来防止SQL注入,另外通过这段SQL你还知道在Oracle数据库中如何对查询到的结果进行分页处理。

  在处理完这些后,我们再来看看当前VehicleOrderPlanRepository继承的接口是在哪里进行定义的?具体的领域层又该如何进行调用?

public interface IVehicleOrderPlanDapperRepository : IDapperRepository<VehicleOrderPlan> {
       IEnumerable<WeeklyOrderPlanSummary> GetWeeklyOrderPlanSummary(int? yearOfPlan, int? weekOfPlan, string provinceName,
           [CanBeNull] VehicleOrderPlanType[] planType, string marketName, PageRequest page);
   }

  这个接口非常简单,但是这个接口究竟应该在哪里进行定义呢?我们按照DDD思想,首先想到的就是在领域层进行定义,不然领域层其它业务该在哪里调用这个方法呢?那么这个可以从哪里找到答案呢?

如何在Asp.Net项目中使用ABP Dapper

关于如何在Asp.Net项目中使用ABP Dapper问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注亿速云行业资讯频道了解更多相关知识。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI