簡體   English   中英

如何 map 來自 postresql 中的存儲過程的結果集,我使用 Entity Framework Core 返回多個游標

[英]How to map set of results from stored procedure in postresql where I return multiple cursors using Entity Framework Core

我正在處理存儲過程以從數據庫中獲取一些統計信息,但我不想在代碼端執行它,因為有很多數據要處理,並且有一些表我需要在執行后調用,還有很多東西將使用資源並且可以通過數據庫查詢廉價地制作。 所以我想出了看起來像這樣的存儲過程:

CREATE OR REPLACE FUNCTION PUBLIC.get_statistics_info(severityref refcursor, eventsref refcursor) 
    RETURNS SETOF refcursor 
    LANGUAGE 'plpgsql'
AS $BODY$ 
                                
BEGIN
    OPEN severityref FOR 
        SELECT 
            si."VarId", si."Date", si."SystemId", si."SystemName", 
            SUM(ss."InfoCounter") AS info, SUM(ss."WarningCounter") AS warn, SUM(ss."NonFatalCounter") AS nfatal, SUM(ss."FatalCounter") AS fatal,
            SUM(ssm."InfoCounter") AS minfo, SUM(ssm."WarningCounter") AS mwarn, SUM(ssm."NonFatalCounter") AS nfatal, SUM(ssm."FatalCounter") AS mfatal
        FROM "StatisticsInfo" AS si
        left JOIN "StatisticsSeverity" AS ss ON si."Id" = ss."StatisticsInfoId"
        left JOIN "StatisticsSeverityMaintenance" AS ssm ON si."Id" = ssm."StatisticsInfoId"
        GROUP BY si."VarId", si."Date", si."SystemId", si."SystemName"; 
    RETURN NEXT severityref;                                                                            

    OPEN eventsref for 
        SELECT 
            si."VarId", si."SystemId" ,
            se."EventId" AS eventid, se."Counter" AS eventcounter, sed."Symbol" AS eventsymbol,
            sem."EventId" AS mseventid, sem."Counter" AS mseventcounter, msed."Symbol" AS meventsymbol
        FROM "StatisticsInfo" AS si
        left JOIN "StatisticsEvent" AS se ON si."Id" = se."StatisticsInfoId"
        LEFT JOIN "EventDefinitions" AS sed ON se."EventId" = sed."Decimal"
        left JOIN "StatisticsEventMaintenance" AS sem ON si."Id" = sem."StatisticsInfoId"
        LEFT JOIN "EventDefinitions" AS msed ON sem."EventId" = msed."Decimal";  
    RETURN NEXT eventsref;   
END
$BODY$;

它使用 2 個游標匯總統計信息,因此我應該得到 2 組數據作為結果。 但是現在我有一個問題如何接收它。 我正在為我的數據庫操作使用實體框架核心,所以我做了這樣的事情。

服務電話:

    public async ValueTask<IEnumerable<object>> GetCombinedStatisticsInfo()
    {
        try
        {
            using var unitOfWork = UnitOfWorkFactory.CreateGeneralContext();

            //I MADE THIS MAPPING AS TEST TO CHECK WHAT WILL BE RETURNED
            var map = new Func<DbDataReader, object>(reader => new
            {
                first = reader[0]
            });

            const string procedureCall = "BEGIN; SELECT get_statistics_info('severity', 'events'); FETCH ALL IN \"severity\"; FETCH ALL IN \"events\"; COMMIT;";
            var result = await unitOfWork.GeneralRepository.ExecuteSqQuery(procedureCall, map);
            unitOfWork.Dispose();
            return result;
        }
        catch (Exception ex)
        {
            logger.Error(ex);
            throw;
        }
    }

存儲庫:

    public async ValueTask<IEnumerable<TResponse>> ExecuteSqlProcedure<TResponse>(string procedureCall, Func<DbDataReader, TResponse> map)
    {
        var transaction = await this.Context.Database.BeginTransactionAsync();
        var result = await ExecuteSql(procedureCall, map, CommandType.StoredProcedure);
        await transaction.CommitAsync();
        return result;
    }

    private async ValueTask<IEnumerable<TResponse>> ExecuteSql<TResponse>(string query, Func<DbDataReader, TResponse> map, CommandType commandType)
    {
        await using var command = this.Context.Database.GetDbConnection().CreateCommand();
        command.CommandText = query;
        command.CommandType = commandType;

        await this.Context.Database.OpenConnectionAsync();
        await using var result = await command.ExecuteReaderAsync();
        var entities = new List<TResponse>();

        while (await result.ReadAsync())
        {
            entities.Add(map(result));
        }

        return entities;
    }

好吧,基本上它執行程序,但結果我得到 cursor 名稱,如:{first: "severity"; 首先:“事件”},所以我檢查了我的數據庫上的執行情況,它可以工作,我使用該事務獲取 2 組數據。 所以我的問題是我在這里做錯了什么?

所以我發現我需要在單獨執行存儲過程和 map 結果之后在事務中添加每個提取,例如:

    public async ValueTask<Dictionary<string, List<object>>> ExecuteGetStatisticsProcedure()
    {
        var transaction = await this.Context.Database.BeginTransactionAsync();
        var entities = new Dictionary<string, List<object>>
        {
            {SeverityKey, new List<object>() },
            {EventsKey, new List<object>() }
        };

        try
        {
            async Task GetSeverity(DbCommand severityCommand)
            {
                const string fetchSeverityCursor = "FETCH ALL IN \"severity\";";
                severityCommand.CommandText = fetchSeverityCursor;
                await using var result = await severityCommand.ExecuteReaderAsync();
                while (await result.ReadAsync())
                {
                    entities[SeverityKey].Add(
                        new
                        {
                            //Map results
                        });
                }
            }

            async Task GetEvents(DbCommand eventsCommand)
            {
                const string fetchEventCursor = "FETCH ALL IN \"events\";";
                eventsCommand.CommandText = fetchEventCursor;

                await eventsCommand.ExecuteReaderAsync();
                await using var eventsResult = await eventsCommand.ExecuteReaderAsync();
                while (await eventsResult.ReadAsync())
                {
                    entities[EventsKey].Add(
                        new
                        {
                            //Map results
                        });
                }
            }

            await using var command = this.Context.Database.GetDbConnection().CreateCommand();
            command.CommandType = CommandType.Text;
            await this.Context.Database.OpenConnectionAsync();

            const string procedureCallProcedure = "SELECT * From get_statistics_info(\'severity\', \'events\');";
            await this.Context.Database.ExecuteSqlRawAsync(procedureCallProcedure);

            await GetSeverity(command);
            await GetEvents(command);

            await transaction.CommitAsync();
        }
        catch (Exception ex)
        {
            Logger.Error(ex);
            await transaction.RollbackAsync();
        }

        return entities;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM