繁体   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