You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何复用LINQ查询处理同库中不同Serilog日志表?

消除Serilog日志表重复LINQ查询代码的方案

问题背景

数据库包含多个Schema完全一致的Serilog专属日志表(如Weather_StructureLog、Store_StructureLog),使用LINQPad监控这些表的近期日志时,当前代码需通过switch语句针对不同表编写重复的LINQ查询逻辑,新增表时必须复制粘贴代码块,维护成本高。

已实现动态获取TypedDataContext的方法:

TypedDataContext SetDynamicConnection(string databaseName)
{
    new { ServerName, databaseName }.Dump("Connection Info");
    var dynamicConnection = new SqlConnection($"Data Source={ServerName};Integrated Security=SSPI;Initial Catalog={databaseName};app=LinqPad");

    return new TypedDataContext(dynamicConnection);
}

当前存在重复逻辑的代码:

var baseQueryable = new List<SerilogSchemaTable>();

switch (tableName)
{
    case "Weather_StructureLog":
        {
            baseQueryable =
            dbContext.Weather_StructureLog
                .Where(ln => ln.TimeStamp > DateTime.Now.AddMonths(-1))
                .OrderByDescending(ln => ln.Id)
                .Select(ln => new SerilogSchemaTable()
                {
                    Exception = ln.Exception,
                    Id = ln.Id,
                    Level = ln.Level,
                    Message = ln.Message,
                    MessageTemplate = ln.MessageTemplate,
                    Properties = ln.Properties,
                    TimeStamp = ln.TimeStamp
                })
                .ToList<SerilogSchemaTable>();
            break;
        }
    case "Store_StructureLog":
        {
            baseQueryable =
            dbContext.Store_StructureLog
                .Where(ln => ln.TimeStamp > DateTime.Now.AddMonths(-1))
                .OrderByDescending(ln => ln.Id)
                .Select(ln => new SerilogSchemaTable()
                {
                    Exception = ln.Exception,
                    Id = ln.Id,
                    Level = ln.Level,
                    Message = ln.Message,
                    MessageTemplate = ln.MessageTemplate,
                    Properties = ln.Properties,
                    TimeStamp = ln.TimeStamp
                })
                .ToList<SerilogSchemaTable>();
            break;
        }
}

解决方案

通过接口抽象+反射缓存的方式统一查询逻辑,彻底消除重复代码:

1. 定义通用日志接口

创建包含所有日志表共同属性的接口,让所有日志实体类实现该接口(LINQPad中可通过编辑实体类的部分类实现):

public interface ISerilogLog
{
    int Id { get; }
    DateTime TimeStamp { get; }
    string Level { get; }
    string Message { get; }
    string MessageTemplate { get; }
    string Exception { get; }
    string Properties { get; }
}

2. 编写通用日志查询方法

实现通用方法,通过反射获取指定表的查询对象,执行统一LINQ逻辑,并加入缓存避免重复反射开销:

// 缓存表属性信息,避免重复反射
private static readonly Dictionary<string, PropertyInfo> _tablePropertyCache = new Dictionary<string, PropertyInfo>();

List<SerilogSchemaTable> GetLogs(TypedDataContext dbContext, string tableName)
{
    // 从缓存获取或反射获取表对应的属性
    if (!_tablePropertyCache.TryGetValue(tableName, out var tableProperty))
    {
        tableProperty = dbContext.GetType().GetProperty(tableName);
        if (tableProperty == null)
            throw new ArgumentException($"日志表 {tableName} 未在DataContext中找到");
        
        _tablePropertyCache[tableName] = tableProperty;
    }

    // 获取表的IQueryable实例
    var queryable = tableProperty.GetValue(dbContext) as IQueryable;
    if (queryable == null)
        throw new InvalidOperationException($"属性 {tableName} 不是有效的IQueryable类型");

    // 转换为通用接口类型并执行统一查询
    return queryable.Cast<ISerilogLog>()
        .Where(ln => ln.TimeStamp > DateTime.Now.AddMonths(-1))
        .OrderByDescending(ln => ln.Id)
        .Select(ln => new SerilogSchemaTable()
        {
            Exception = ln.Exception,
            Id = ln.Id,
            Level = ln.Level,
            Message = ln.Message,
            MessageTemplate = ln.MessageTemplate,
            Properties = ln.Properties,
            TimeStamp = ln.TimeStamp
        })
        .ToList();
}

3. 替换原有重复代码

原来的switch语句可简化为一行调用:

var baseQueryable = GetLogs(dbContext, tableName);

后续维护

新增日志表时,只需:

  • 确保对应实体类实现ISerilogLog接口
  • 直接传入新表名调用GetLogs方法即可,无需修改查询逻辑代码

内容的提问来源于stack exchange,提问作者MADCookie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 06:23:10