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

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;
}
}
}