在实际的项目中,除了集成ABP框架的EntityFrameworkCore以外,在有些特定的场景下不可避免地会使用一些SQL查询语句,一方面是由于现在的EntityFrameworkCore2.X有些问题没有解决,另外一方面是基于性能方面的考虑,在了解本篇内容之前,首先还是来看看官方文档来给出的说明。
按照官方的介绍整体可以分为下面的步骤:1 安装依赖包。2 添加DependsOn属性标签。3 Entity to Table Mapping。 4 Usage 通过上面的4个步骤我们就能够正常在Asp.Net Core项目中使用ABP Dapper了,下面我们就具体的过程来做进一步的说明。
一 安装包依赖
这个不做过多的解释,通过Nuget 包管理器或者通过程序包管理控制台来添加Abp.Dapper的引用,在我们实际的项目中整个类库的结构如下图所示,包含Dapper和EntityFrameworkCore两种方案。
二 添加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{ typeof(SalesDataModule).GetAssembly() }); } }
这里我们应该了解为什么要添加依赖关系?这个我们当前的SalesDataModule会依赖于AbpDapperModule和AbpZeroCoreEntityFrameworkCoreModule,确立了这样的依赖关系后,在ABP框架中就会将当前Module所依赖的其它Module放到List
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{ public VehicleOrderPlanMapper() { Table("VehicleOrderPlan"); Map(x => x.Branch).Ignore(); AutoMap(); } }
四 应用
这个部分就结合具体的项目来谈一谈一些细节方面的东西,我们先来看看具体的代码。
public class VehicleOrderPlanDapperRepository : DcsDapperRepositoryBase, IVehicleOrderPlanDapperRepository { public VehicleOrderPlanDapperRepository(IActiveTransactionProvider activeTransactionProvider) : base(activeTransactionProvider) { } public IEnumerable 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 (sql, page, new { yearOfPlan, weekOfPlan, provinceName, marketName }); } }
这段代码主要是通过具体传入的参数计划年、计划周、省份......等参数到数据库中查询相关的记录,这里我们先看看基类DcsDapperRepositoryBase
public class DcsDapperRepositoryBase: DapperEfRepositoryBase where TEntity : class, IEntity { public DcsDapperRepositoryBase(IActiveTransactionProvider activeTransactionProvider) : base(activeTransactionProvider) { } /// /// 以分页的形式查询数据 /// ////// /// /// 参数的匿名对象 /// protected IEnumerable QueryPaged (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 (pagedSql, parameters); } }
在这个基类中我们继承了ABP中的基类DapperEfRepositoryBase
在处理完这些后,我们再来看看当前VehicleOrderPlanRepository继承的接口是在哪里进行定义的?具体的领域层又该如何进行调用?
public interface IVehicleOrderPlanDapperRepository : IDapperRepository{ IEnumerable GetWeeklyOrderPlanSummary(int? yearOfPlan, int? weekOfPlan, string provinceName, [CanBeNull] VehicleOrderPlanType[] planType, string marketName, PageRequest page); }
这个接口非常简单,但是这个接口究竟应该在哪里进行定义呢?我们按照DDD思想,首先想到的就是在领域层进行定义,不然领域层其它业务该在哪里调用这个方法呢?那么这个可以从哪里找到答案呢?
有没有对这张图很熟悉,这个就是用于介绍ABP N层架构的示意图,红框标注的就是具体的结构中的接口定义和实现,这两者的定义和实现分别是处于不同的层中,一个属于Domain Layer中而具体的实现位于Infrastructure Layer中,一层定义接口,而另外一层则定义具体的实现,有了这个你是不是对整个ABP的架构有了更深入的理解呢?
以上就是如何在Asp.Net Core中集成ABP Dapper的详细内容,更多关于Asp.Net Core中集成ABP Dapper的资料请关注脚本之家其它相关文章!