实现 EF Core 6 自定义查询标记

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了实现 EF Core 6 自定义查询标记相关的知识,希望对你有一定的参考价值。

前言

在《EF Core使用Simple Logging输出日志》中,我们介绍了查询标记 TagWith,它可以帮助我们快速定位到需要的日志:

而在 .NET 6 中,新增了另外一个查询标记 TagWithCallSite,它可以标记出代码的位置:

var user = await new DefaultDbContext().User
    .Where(p => p.Name == "My IO")
    .TagWith("Find My IO")
    .TagWithCallSite()
    .FirstOrDefaultAsync();

那它是怎么做到的呢?

原理探究

查看 TagWithCallSite 的源代码:

public static IQueryable<T> TagWithCallSite<T>(
        this IQueryable<T> source,
        [NotParameterized] [CallerFilePath] string? filePath = null,
        [NotParameterized] [CallerLineNumber] int lineNumber = 0)

原来,它使用了 CallerFilePathAttributeCallerLineNumberAttribute 来获取包含调用方的源文件完整路径和调用方法的行号。

原理利用

这让我们想到了,在《.NET 6新特性试用 | ArgumentNullException卫语句》中发现的 CallerArgumentExpressionAttribute,它可以获取执行的表达式。

通过添加此 Attribute,我们可以创建自己的自定义查询标记。实现代码如下:

public static IQueryable<T> TagWithCallInfo<T>(this IQueryable<T> source,
            string? tag = null,
            [NotParameterized][CallerArgumentExpression("source")] string? argument = null,
            [NotParameterized][CallerMemberName] string? memberName = null,
            [NotParameterized][CallerFilePath] string? filePath = null,
            [NotParameterized][CallerLineNumber] int lineNumber = 0)

    var stringBuilder = new StringBuilder();

    stringBuilder.AppendLine(tag);

    foreach (var str in argument.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries))
    
        stringBuilder.AppendLine(str);
    
    stringBuilder.AppendLine($@"at memberName");
    stringBuilder.AppendLine($@"File: filePath:lineNumber");

    return source.TagWith(stringBuilder.ToString());

该方法不仅包含自定义标记文本,还自动包括了被调用的 LINQ 查询表达式、方法名称、文件路径、行号。

Demo

运行下列代码进行验证,完全满足了我们的要求:

var user = await new DefaultDbContext().User
    .Where(p => p.Name == "My IO")    
    .TagWithCallInfo("Find My IO")
    .FirstOrDefaultAsync();

结论

今天,通过扩展 TagWithCallSite ,我们实现了自定义查询标记。

添加微信号【MyIO666】,邀你加入技术交流群

以上是关于实现 EF Core 6 自定义查询标记的主要内容,如果未能解决你的问题,请参考以下文章

ef core实现软删除

给 EF Core 查询增加 With NoLock

如何在 EF Core 5 中为自定义 SQL 配置导航属性

我可以重用代码来为 EF Core 的子属性选择自定义 DTO 对象吗?

EF core (code first) 通过自定义 Migration History 实现多租户使用同一数据库时更新数据库结构

EF Core 6 新功能汇总