在ABP中通過EF直接執行原生Sql的解決方案


一般情況下,使用EF中的查詢語法和方法語法可以幫助我們完成絕大部分業務,但是也有特殊的情況需要直接執行Sql語句。比如,我們的業務過於復雜繁瑣,或是有些業務使用EF操作時比較復雜,但是使用Sql時會很簡單等等。

今天做項目的時候,就由於使用EF來處理邏輯時格外棘手,最終選擇了直接執行Sql語句,下面說說具體的業務。

一共關系到三張表,分別是Operators(運營商表),Orders(訂單表)和DeviceCoinsRecords(設備投幣記錄表),相應表的定義已經截圖如下,就不在這里編寫代碼了。Operators里放運營商的數據信息,Orders是手機端掃碼下單時產生的訂單數據,DeviceCoinsRecords是向機器設備投幣時產生的數據。

用下面的一張圖解釋一下:

圖片

下面是三張表的結構:

圖片

圖片

圖片

三張表之間的關聯關系是:Orders和和DeviceCoinsRecords通過OperatorId關聯Operators表的Id主鍵。

要實現的業務是:

Sql語句表達:

SELECT ROW_NUMBER() OVER(ORDER BY Id ) AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id  AND YEAR(OrderDate)=@Year1 AND MONTH(OrderDate)=@Month1) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year2 AND Month=@Month2) AS TotalCoinsCast
 FROM dbo.Operators

視圖表達:
圖片

自然語言表達:

匯總運營商的年度和月度報表,也可選擇具體的運營商和年月進行匯總。

一開始我是拒絕在EF中使用SQL查詢的,但是花了好長時間,實在是找不到可以替代以上sql的linq語句或者Lambda方法語法,有哪位能寫出來的,歡迎挑戰一下,但是寫出來的很復雜的話,也沒這個必要了。

下面說說具體的實現【首先要聲明的是我使用的是ABP框架】。

1.在核心層(Core層)的IRepositories文件下創建一個接口IOperatorReportRepository

圖片

2.該接口的定義如下代碼所示:

  public interface IOperatorReportRepository:IRepository<Operators>
    {
        Task<IEnumerable<OperatorYearOrMonthReport>> QueryMonthReports(int year, int month, int operatorId);
        Task<IEnumerable<OperatorYearOrMonthReport>> QueryYearReports(int year, int operatorId);
    }

3.實現接口代碼:

 public class OperatorReportReposiroty:ChargeStationRepositoryBase<Operators>,IOperatorReportRepository
    {
        public OperatorReportReposiroty(IDbContextProvider<ChargeStationDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
            
        }
        public async Task<IEnumerable<OperatorYearOrMonthReport>> QueryMonthReports(int year, int month,int operatorId=0)
        {
            string whereClause = string.Empty;
            if (operatorId>0)
            {
                whereClause += string.Format(" where Id={0} ",operatorId);
            }
            string sql = string.Format(@"
SELECT ROW_NUMBER() OVER(ORDER BY Id ) AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id  AND YEAR(OrderDate)=@Year1 AND MONTH(OrderDate)=@Month1) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year2 AND Month=@Month2) AS TotalCoinsCast
 FROM dbo.Operators {0}", whereClause);
            return await Context.Database.SqlQuery<OperatorYearOrMonthReport>(sql, 
                new SqlParameter("@Year1", year), 
                new SqlParameter("@Month1", month),
                new SqlParameter("@Year2", year), 
                new SqlParameter("@Month2", month)).ToListAsync();

        }


        public async Task<IEnumerable<OperatorYearOrMonthReport>> QueryYearReports(int year, int operatorId = 0)
        {
            string whereClause = string.Empty;
            if (operatorId>0)
            {
                whereClause += string.Format(" where Id={0} ", operatorId);
            }
            string sql = string.Format(@"
SELECT ROW_NUMBER() OVER(ORDER BY Id )AS RowId,Id,Name,AllocateRatio,
(SELECT SUM(PayFee) FROM dbo.Orders WHERE Status NOT IN(0,3,4) AND OperatorID=dbo.Operators.Id AND YEAR(OrderDate)=@Year3) AS TotalScanCode,
(SELECT SUM(TheDayMoney) FROM dbo.DeviceCoinsRecords WHERE dbo.DeviceCoinsRecords.OperatorID=dbo.Operators.Id AND Year=@Year4) AS TotalCoinsCast
 FROM dbo.Operators {0}", whereClause);
            
            return await Context.Database.SqlQuery<OperatorYearOrMonthReport>(sql, 
                new SqlParameter("@Year3", year),
                new SqlParameter("@Year4", year)).ToListAsync();

        }
    }

這里有點意思的是,如果SqlQuery的后面沒有ToList()或者ToListAsync(),那么你會收獲一個奇妙的禮物!你可以試試看!

4.在應用服務層調用

  public async Task<PagedResultOutput<GetOperatorReportsOutput>> GetOperatorReports(GetOperatorReportsInput input)
        {
           
            int operatorId = string.IsNullOrEmpty(input.Code)
                ? 0 : _operatorRepository.GetAll().Single(o => o.Code == input.Code).Id;
            IEnumerable<OperatorYearOrMonthReport> operatorMonthReports;
            if (input.Year.HasValue && input.Month.HasValue)
            {
                operatorMonthReports =await _operatorReportRepository.QueryMonthReports(input.Year.Value,input.Month.Value,operatorId);
            }else if (input.Year.HasValue)
            {
                operatorMonthReports =await _operatorReportRepository.QueryYearReports(input.Year.Value,operatorId);
            }
            else
            {
                if (input.IsThisYear)
                {
                    operatorMonthReports = await _operatorReportRepository.QueryYearReports(DateTime.Now.Year,operatorId);
                }
                else
                {
                    operatorMonthReports =await  _operatorReportRepository.QueryMonthReports(DateTime.Now.Year,DateTime.Now.Month,operatorId);
                }
            }
            var totalCount = operatorMonthReports.Count();
            var operatorReportOutputList = operatorMonthReports.MapTo<List<GetOperatorReportsOutput>>();
            return new PagedResultOutput<GetOperatorReportsOutput>(totalCount, operatorReportOutputList);
        }

好了,這次主要記錄一下在EF中如何直接調用Sql語句的用法,以后有機會再說說關於在EF中存儲過程(包括輸出參數的情況)的調用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM