You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
12 KiB
323 lines
12 KiB
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Logging;
|
|
using CellularManagement.Domain.Entities.Logging;
|
|
using CellularManagement.Domain.Entities.Device;
|
|
using CellularManagement.Domain.Repositories.Logging;
|
|
using CellularManagement.Domain.Repositories.Base;
|
|
using CellularManagement.Infrastructure.Repositories.Base;
|
|
using CellularManagement.Domain.Models;
|
|
using System.Linq;
|
|
using X1.Domain.Entities.Logging;
|
|
|
|
namespace CellularManagement.Infrastructure.Repositories.Logging;
|
|
|
|
/// <summary>
|
|
/// 协议日志仓储实现类
|
|
/// </summary>
|
|
public class ProtocolLogRepository : BaseRepository<ProtocolLog>, IProtocolLogRepository
|
|
{
|
|
private readonly ILogger<ProtocolLogRepository> _logger;
|
|
|
|
/// <summary>
|
|
/// 构造函数
|
|
/// </summary>
|
|
/// <param name="commandRepository">命令仓储</param>
|
|
/// <param name="queryRepository">查询仓储</param>
|
|
/// <param name="logger">日志记录器</param>
|
|
public ProtocolLogRepository(
|
|
ICommandRepository<ProtocolLog> commandRepository,
|
|
IQueryRepository<ProtocolLog> queryRepository,
|
|
ILogger<ProtocolLogRepository> logger)
|
|
: base(commandRepository, queryRepository, logger)
|
|
{
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据设备代码获取协议日志
|
|
/// </summary>
|
|
/// <param name="deviceCode">设备代码</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表</returns>
|
|
public async Task<IEnumerable<ProtocolLog>> GetByDeviceCodeAsync(string deviceCode, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var logs = await QueryRepository.FindAsync(
|
|
p => p.DeviceCode == deviceCode,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return logs.OrderByDescending(p => p.Timestamp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取设备代码 {DeviceCode} 的协议日志时发生错误", deviceCode);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据运行时代码获取协议日志
|
|
/// </summary>
|
|
/// <param name="runtimeCode">运行时代码</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表</returns>
|
|
public async Task<IEnumerable<ProtocolLog>> GetByRuntimeCodeAsync(string runtimeCode, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var logs = await QueryRepository.FindAsync(
|
|
p => p.RuntimeCode == runtimeCode,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return logs.OrderByDescending(p => p.Timestamp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取运行时代码 {RuntimeCode} 的协议日志时发生错误", runtimeCode);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据设备代码和运行时代码获取协议日志
|
|
/// </summary>
|
|
/// <param name="deviceCode">设备代码</param>
|
|
/// <param name="runtimeCode">运行时代码</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表</returns>
|
|
public async Task<IEnumerable<ProtocolLog>> GetByDeviceAndRuntimeCodeAsync(string deviceCode, string runtimeCode, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var logs = await QueryRepository.FindAsync(
|
|
p => p.DeviceCode == deviceCode && p.RuntimeCode == runtimeCode,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return logs.OrderByDescending(p => p.Timestamp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取设备代码 {DeviceCode} 和运行时代码 {RuntimeCode} 的协议日志时发生错误", deviceCode, runtimeCode);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据时间范围获取协议日志
|
|
/// </summary>
|
|
/// <param name="startTimestamp">开始时间戳</param>
|
|
/// <param name="endTimestamp">结束时间戳</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表</returns>
|
|
public async Task<IEnumerable<ProtocolLog>> GetByTimeRangeAsync(long startTimestamp, long endTimestamp, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var logs = await QueryRepository.FindAsync(
|
|
p => p.Timestamp >= startTimestamp && p.Timestamp <= endTimestamp,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return logs.OrderByDescending(p => p.Timestamp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取时间范围 {StartTimestamp} 到 {EndTimestamp} 的协议日志时发生错误", startTimestamp, endTimestamp);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据协议层类型获取协议日志
|
|
/// </summary>
|
|
/// <param name="layerType">协议层类型</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表</returns>
|
|
public async Task<IEnumerable<ProtocolLog>> GetByLayerTypeAsync(ProtocolLayer layerType, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
var logs = await QueryRepository.FindAsync(
|
|
p => p.LayerType == layerType,
|
|
cancellationToken: cancellationToken);
|
|
|
|
return logs.OrderByDescending(p => p.Timestamp);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取协议层类型 {LayerType} 的协议日志时发生错误", layerType);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 根据设备代码和运行时状态获取协议日志(高性能查询,不包含MessageDetailJson)
|
|
/// </summary>
|
|
/// <param name="deviceCode">设备代码</param>
|
|
/// <param name="runtimeCodes">运行时代码集合</param>
|
|
/// <param name="startTimestamp">开始时间戳</param>
|
|
/// <param name="endTimestamp">结束时间戳</param>
|
|
/// <param name="layerTypes">协议层类型数组</param>
|
|
/// <param name="runtimeStatuses">运行时状态过滤(可选,支持多个状态)</param>
|
|
/// <param name="orderByDescending">是否按时间戳降序排序</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>协议日志列表DTO</returns>
|
|
public async Task<IEnumerable<ProtocolLogListDto>> GetByDeviceWithFiltersAsync(
|
|
string? deviceCode,
|
|
IEnumerable<string>? runtimeCodes = null,
|
|
long? startTimestamp = null,
|
|
long? endTimestamp = null,
|
|
IEnumerable<int>? layerTypes = null,
|
|
IEnumerable<int>? runtimeStatuses = null,
|
|
bool orderByDescending = true,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
// 构建 SQL 查询 - 先过滤运行时状态,再进行JOIN
|
|
var sql = @"
|
|
SELECT
|
|
pl.""Id"",
|
|
pl.""MessageId"",
|
|
pl.""LayerType"",
|
|
pl.""CellID"",
|
|
pl.""IMSI"",
|
|
pl.""Direction"",
|
|
pl.""UEID"",
|
|
pl.""PLMN"",
|
|
pl.""TimeMs"",
|
|
pl.""Timestamp"",
|
|
pl.""Info"",
|
|
pl.""Message"",
|
|
pl.""DeviceCode"",
|
|
pl.""RuntimeCode""
|
|
FROM ""tb_protocol_logs"" pl
|
|
INNER JOIN (
|
|
SELECT DISTINCT cdr.""RuntimeCode""
|
|
FROM ""tb_cellular_device_runtimes"" cdr
|
|
INNER JOIN ""tb_cellular_device_runtime_details"" cdr_detail
|
|
ON cdr.""RuntimeCode"" = cdr_detail.""RuntimeCode""
|
|
WHERE 1=1";
|
|
|
|
var parameters = new List<object>();
|
|
var paramIndex = 0;
|
|
|
|
// 添加设备代码过滤到子查询
|
|
if (!string.IsNullOrEmpty(deviceCode))
|
|
{
|
|
sql += $" AND cdr.\"DeviceCode\" = {{{paramIndex}}}";
|
|
parameters.Add(deviceCode);
|
|
paramIndex++;
|
|
}
|
|
|
|
// 添加运行时状态过滤到子查询
|
|
if (runtimeStatuses != null && runtimeStatuses.Any())
|
|
{
|
|
var statusList = string.Join(" OR ", runtimeStatuses.Select(status => $"cdr.\"RuntimeStatus\" = {status}"));
|
|
sql += $" AND ({statusList})";
|
|
}
|
|
|
|
// 添加运行时编码过滤到子查询
|
|
if (runtimeCodes != null && runtimeCodes.Any())
|
|
{
|
|
var runtimeCodeList = string.Join(",", runtimeCodes.Select((_, i) => $"{{{paramIndex + i}}}"));
|
|
sql += $" AND cdr.\"RuntimeCode\" IN ({runtimeCodeList})";
|
|
parameters.AddRange(runtimeCodes);
|
|
paramIndex += runtimeCodes.Count();
|
|
}
|
|
|
|
// 关闭子查询
|
|
sql += @"
|
|
) filtered_runtimes ON pl.""RuntimeCode"" = filtered_runtimes.""RuntimeCode""";
|
|
|
|
// 添加主查询的过滤条件
|
|
if (!string.IsNullOrEmpty(deviceCode))
|
|
{
|
|
sql += $" WHERE pl.\"DeviceCode\" = {{{paramIndex}}}";
|
|
parameters.Add(deviceCode);
|
|
paramIndex++;
|
|
}
|
|
else
|
|
{
|
|
sql += " WHERE 1=1";
|
|
}
|
|
|
|
// 添加时间范围过滤
|
|
if (startTimestamp.HasValue)
|
|
{
|
|
sql += $" AND pl.\"Timestamp\" >= {{{paramIndex}}}";
|
|
parameters.Add(startTimestamp.Value);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (endTimestamp.HasValue)
|
|
{
|
|
sql += $" AND pl.\"Timestamp\" <= {{{paramIndex}}}";
|
|
parameters.Add(endTimestamp.Value);
|
|
paramIndex++;
|
|
}
|
|
|
|
// 添加协议层类型过滤
|
|
if (layerTypes != null && layerTypes.Any())
|
|
{
|
|
var layerTypeList = string.Join(",", layerTypes.Select((_, i) => $"{{{paramIndex + i}}}"));
|
|
sql += $" AND pl.\"LayerType\" IN ({layerTypeList})";
|
|
foreach (var layerType in layerTypes)
|
|
{
|
|
parameters.Add(layerType);
|
|
}
|
|
}
|
|
|
|
// 添加排序
|
|
if (orderByDescending)
|
|
{
|
|
sql += " ORDER BY pl.\"Timestamp\" DESC";
|
|
}
|
|
else
|
|
{
|
|
sql += " ORDER BY pl.\"Timestamp\" ASC";
|
|
}
|
|
|
|
// 执行 SQL 查询,直接映射到ProtocolLogListDto
|
|
var logs = await QueryRepository.ExecuteSqlQueryAsync<ProtocolLogListDto>(sql, parameters.ToArray(), cancellationToken);
|
|
return logs;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取设备代码 {DeviceCode} 的协议日志列表时发生错误", deviceCode);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据协议日志ID获取MessageDetailJson
|
|
/// </summary>
|
|
/// <param name="id">协议日志ID</param>
|
|
/// <param name="cancellationToken">取消令牌</param>
|
|
/// <returns>MessageDetailJson内容</returns>
|
|
public async Task<string?> GetMessageDetailJsonByIdAsync(string id, CancellationToken cancellationToken = default)
|
|
{
|
|
try
|
|
{
|
|
// 使用SQL查询,只获取MessageDetailJson字段,性能最高
|
|
var sql = @"
|
|
SELECT pl.""MessageDetailJson""
|
|
FROM ""tb_protocol_logs"" pl
|
|
WHERE pl.""Id"" = {0}";
|
|
|
|
var parameters = new[] { id };
|
|
|
|
// 执行SQL查询,只返回MessageDetailJson字段
|
|
var result = await QueryRepository.ExecuteSqlQueryAsync<string>(sql, parameters, cancellationToken);
|
|
|
|
return result.FirstOrDefault();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "获取协议日志ID {Id} 的MessageDetailJson时发生错误", id);
|
|
throw;
|
|
}
|
|
}
|
|
}
|