如何在Asp.Net Core中集成ABP Dapper
在實(shí)際的項(xiàng)目中,除了集成ABP框架的EntityFrameworkCore以外,在有些特定的場(chǎng)景下不可避免地會(huì)使用一些SQL查詢語(yǔ)句,一方面是由于現(xiàn)在的EntityFrameworkCore2.X有些問(wèn)題沒(méi)有解決,另外一方面是基于性能方面的考慮,在了解本篇內(nèi)容之前,首先還是來(lái)看看官方文檔來(lái)給出的說(shuō)明。
按照官方的介紹整體可以分為下面的步驟:1 安裝依賴包。2 添加DependsOn屬性標(biāo)簽。3 Entity to Table Mapping。 4 Usage 通過(guò)上面的4個(gè)步驟我們就能夠正常在Asp.Net Core項(xiàng)目中使用ABP Dapper了,下面我們就具體的過(guò)程來(lái)做進(jìn)一步的說(shuō)明。
一 安裝包依賴
這個(gè)不做過(guò)多的解釋,通過(guò)Nuget 包管理器或者通過(guò)程序包管理控制臺(tái)來(lái)添加Abp.Dapper的引用,在我們實(shí)際的項(xiàng)目中整個(gè)類庫(kù)的結(jié)構(gòu)如下圖所示,包含Dapper和EntityFrameworkCore兩種方案。
二 添加DependsOn屬性標(biāo)簽
后面我們就需要在我們當(dāng)前類庫(kù)項(xiàng)目中唯一的SalesDataModule中來(lái)做一些初始化和添加DependsOn標(biāo)簽的操作了。
[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() }); } }
這里我們應(yīng)該了解為什么要添加依賴關(guān)系?這個(gè)我們當(dāng)前的SalesDataModule會(huì)依賴于AbpDapperModule和AbpZeroCoreEntityFrameworkCoreModule,確立了這樣的依賴關(guān)系后,在ABP框架中就會(huì)將當(dāng)前Module所依賴的其它Module放到List<AbpModule>的前面,這樣通過(guò)這樣對(duì)的層層依賴關(guān)系進(jìn)行拓?fù)渑判蚓湍軌虮WC被依賴的AbpModule一定先進(jìn)行初始化操作,這樣就能夠避免引用關(guān)系的錯(cuò)誤,從而導(dǎo)致代碼邏輯的錯(cuò)誤,具體說(shuō)來(lái):如果A 依賴于B,B依賴于C,那么這三個(gè)模塊之間的排序?yàn)镃 B A,這樣在整個(gè)Module系統(tǒng)初始化的時(shí)候,會(huì)先執(zhí)行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()); }
這個(gè)里面sortedModules就是通過(guò)這種依賴關(guān)系進(jìn)行拓?fù)渑判虻?,然后依次這行每個(gè)模塊中的這幾個(gè)方法進(jìn)行一些初始化的操作。
三 Entity to Table Mapping
這個(gè)按照官方的解釋就是在建立Entity和數(shù)據(jù)庫(kù)實(shí)體之間的關(guān)系,這個(gè)類似于在Domain層實(shí)體上面添加【Table】標(biāo)簽(個(gè)人理解),在這個(gè)里面我們還能添加一些其它特性,比如Ignore掉一些導(dǎo)航屬性等等......
public sealed class VehicleOrderPlanMapper : ClassMapper<VehicleOrderPlan> { public VehicleOrderPlanMapper() { Table("VehicleOrderPlan"); Map(x => x.Branch).Ignore(); AutoMap(); } }
四 應(yīng)用
這個(gè)部分就結(jié)合具體的項(xiàng)目來(lái)談一談一些細(xì)節(jié)方面的東西,我們先來(lái)看看具體的代碼。
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.周度計(jì)劃, VehicleOrderPlanType.小品種計(jì)劃, VehicleOrderPlanType.移庫(kù)計(jì)劃 }; 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 }); } }
這段代碼主要是通過(guò)具體傳入的參數(shù)計(jì)劃年、計(jì)劃周、省份......等參數(shù)到數(shù)據(jù)庫(kù)中查詢相關(guān)的記錄,這里我們先看看基類DcsDapperRepositoryBase<VehicleOrderPlan>里面做了些什么?
public class DcsDapperRepositoryBase<TEntity> : DapperEfRepositoryBase<DcsDbContext, TEntity> where TEntity : class, IEntity<int> { public DcsDapperRepositoryBase(IActiveTransactionProvider activeTransactionProvider) : base(activeTransactionProvider) { } /// <summary> /// 以分頁(yè)的形式查詢數(shù)據(jù) /// </summary> /// <typeparam name="TValueObject"></typeparam> /// <param name="sql"></param> /// <param name="pageRequest"></param> /// <param name="parameters">參數(shù)的匿名對(duì)象</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); } }
在這個(gè)基類中我們繼承了ABP中的基類DapperEfRepositoryBase<DcsDbContext, TEntity>,這個(gè)泛型基類第一個(gè)參數(shù)就是我們項(xiàng)目中的具體DbContext,第二個(gè)參數(shù)就是我們具體定義的實(shí)體,這個(gè)實(shí)體是主鍵為Int的自增長(zhǎng)類型。這里面由于查詢的數(shù)據(jù)非常多,所以我們這里實(shí)際上返回的是分頁(yè)的第一頁(yè)的結(jié)果集,這里還有一個(gè)重要的知識(shí)就是,為了防止sql注入,這里sql中的參數(shù)都采用參數(shù)的匿名對(duì)象,而不是直接進(jìn)行拼接,這個(gè)是防止SQL注入的時(shí)候最常見(jiàn)的方式。通過(guò)這個(gè)具體的例子你應(yīng)該知道怎樣在ABP Dapper中使用匿名參數(shù)對(duì)象來(lái)防止SQL注入,另外通過(guò)這段SQL你還知道在Oracle數(shù)據(jù)庫(kù)中如何對(duì)查詢到的結(jié)果進(jìn)行分頁(yè)處理。
在處理完這些后,我們?cè)賮?lái)看看當(dāng)前VehicleOrderPlanRepository繼承的接口是在哪里進(jìn)行定義的?具體的領(lǐng)域?qū)佑衷撊绾芜M(jìn)行調(diào)用?
public interface IVehicleOrderPlanDapperRepository : IDapperRepository<VehicleOrderPlan> { IEnumerable<WeeklyOrderPlanSummary> GetWeeklyOrderPlanSummary(int? yearOfPlan, int? weekOfPlan, string provinceName, [CanBeNull] VehicleOrderPlanType[] planType, string marketName, PageRequest page); }
這個(gè)接口非常簡(jiǎn)單,但是這個(gè)接口究竟應(yīng)該在哪里進(jìn)行定義呢?我們按照DDD思想,首先想到的就是在領(lǐng)域?qū)舆M(jìn)行定義,不然領(lǐng)域?qū)悠渌鼧I(yè)務(wù)該在哪里調(diào)用這個(gè)方法呢?那么這個(gè)可以從哪里找到答案呢?
有沒(méi)有對(duì)這張圖很熟悉,這個(gè)就是用于介紹ABP N層架構(gòu)的示意圖,紅框標(biāo)注的就是具體的結(jié)構(gòu)中的接口定義和實(shí)現(xiàn),這兩者的定義和實(shí)現(xiàn)分別是處于不同的層中,一個(gè)屬于Domain Layer中而具體的實(shí)現(xiàn)位于Infrastructure Layer中,一層定義接口,而另外一層則定義具體的實(shí)現(xiàn),有了這個(gè)你是不是對(duì)整個(gè)ABP的架構(gòu)有了更深入的理解呢?
以上就是如何在Asp.Net Core中集成ABP Dapper的詳細(xì)內(nèi)容,更多關(guān)于Asp.Net Core中集成ABP Dapper的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
asp.net 實(shí)現(xiàn)防迅雷等下載工具盜鏈
利用IHttpHandler接口來(lái)監(jiān)聽(tīng)對(duì)本網(wǎng)站的資源請(qǐng)求后綴名是否是我們要阻止的文件,如果是再判斷是否有下載權(quán)限。沒(méi)有就給它返回一個(gè)默認(rèn)的無(wú)用的文件。2009-02-02ASP.NET?MVC增加一條記錄同時(shí)添加N條集合屬性所對(duì)應(yīng)的個(gè)體
這篇文章介紹了ASP.NET?MVC增加一條記錄同時(shí)添加N條集合屬性所對(duì)應(yīng)個(gè)體的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08asp.net 動(dòng)態(tài)添加多個(gè)用戶控件
動(dòng)態(tài)添加多個(gè)相同用戶控件,并使每個(gè)用戶控件獲取不同的內(nèi)容。2009-12-12Asp.net MVC 中利用jquery datatables 實(shí)現(xiàn)數(shù)據(jù)分頁(yè)顯示功能
這篇文章主要介紹了Asp.net MVC 中利用jquery datatables 實(shí)現(xiàn)數(shù)據(jù)分頁(yè)顯示功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-06-06c#實(shí)現(xiàn)根據(jù)網(wǎng)絡(luò)IP顯示地理位置功能示例
通常都會(huì)有類似 注冊(cè)IP和最后登錄IP這兩個(gè)的字段來(lái)存儲(chǔ)用戶注冊(cè)時(shí)候的IP地址和最后登錄的IP的地址,現(xiàn)在我們就簡(jiǎn)單的實(shí)現(xiàn)一下如標(biāo)題所示的功能2013-06-06ASP.NET動(dòng)態(tài)增加HTML元素的方法實(shí)例小結(jié)
這篇文章主要介紹了ASP.NET動(dòng)態(tài)增加HTML元素的方法,結(jié)合實(shí)例形式總結(jié)分析了asp.net針對(duì)樣式、Meta、js等元素動(dòng)態(tài)增加相關(guān)操作技巧,需要的朋友可以參考下2017-01-01aspnetcore 實(shí)現(xiàn)簡(jiǎn)單的偽靜態(tài)化功能
這篇文章主要介紹了aspnetcore 實(shí)現(xiàn)簡(jiǎn)單的偽靜態(tài)化功能,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07*.ashx文件不能訪問(wèn)Session值的解決方法
這篇文章主要介紹了*.ashx文件不能訪問(wèn)Session值的解決方法,只需在頭部引用一個(gè)命名空間即可解決問(wèn)題,非常實(shí)用,需要的朋友可以參考下2014-09-09記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案
這篇文章主要介紹了記一次EFCore類型轉(zhuǎn)換錯(cuò)誤及解決方案,幫助大家更好的理解和學(xué)習(xí)使用asp.net core,感興趣的朋友可以了解下2021-03-03