惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
WordPress大学
WordPress大学
罗磊的独立博客
小众软件
小众软件
I
InfoQ
Y
Y Combinator Blog
宝玉的分享
宝玉的分享
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Hugging Face - Blog
Hugging Face - Blog
MyScale Blog
MyScale Blog
博客园 - 聂微东
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园_首页
S
SegmentFault 最新的问题
博客园 - 三生石上(FineUI控件)
P
Proofpoint News Feed
博客园 - 司徒正美
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Microsoft Azure Blog
Microsoft Azure Blog
Jina AI
Jina AI
N
Netflix TechBlog - Medium

博客园 - Rick Carter

官方APP太难用了,所以我写了个 OpenNas App 死锁是怎么发生的,举个简单的例子 hangfire内部执行器是同步的,会导致死锁 缓存读写代码逻辑的正确姿势 dotnet未捕获异常导致系统崩溃问题 dotnet-dump安装、收集dump和崩溃自动收集dump EFCore中巧妙利用ToQueryString()实现批插(不借助第三方包) 修复达梦EFCore驱动布尔类型兼容问题 dotnet使用redis时需要注意的问题 巧用 using 作用域(IDisposable)的生命周期包装特性 实现前后置处理 非托管内存怎么计算? dotnet集合类型性能优化的两个小儿科的知识点 一个前端树形控件联动勾选框卡顿问题及解决 .net c# Func<Task>及变体做为多播委托异步执行会另开线程的问题 利用C#9.0中的record提高性能 dotnet CultureInfo遇到欧洲如俄文小数点是逗号想转点的解决办法 hangfire.entityframeworkcore这个库因为System.Threading.Timer未停止也未释放而导致的性能问题 达梦DM.Microsoft.EntityFreameworkCore查询报错invalid cast from DateTime to DateTimeOffset 达梦DOTNET驱动DM.Provider8.3.1.30495存在空字符串插入变DBNull的问题 是否可以考虑做一个dotnet应用的性能诊断工具
关于EFCore插件API使用中踩过的坑
Rick Carter · 2025-04-21 · via 博客园 - Rick Carter

本文基于efcore8.0,参考文档
假设需要重写efcore或者特定数据库的方法的SQL转换,按上面文档及其示例代码,本例中我们大概就是提供下面几个接口的实现。

  • IMethodCallTranslator
  • IMethodCallTranslatorPlugin
  • IDbContextOptionsExtension
  • 以及特定数据库的DbContextOptionsBuilder(如SqlServerDbContextOptionsBuilder)扩展方法

后面再说说踩过的坑(总结)!

示例

public class MyMethodCallTranslator:IMethodCallTranslator
{
    private readonly SqlServerSqlExpressionFactory _sqlExpressionFactory;
    public MyMethodCallTranslator(SqlServerSqlExpressionFactory sqlExpressionFactory)
    {
        _sqlExpressionFactory=sqlExpressionFactory
    }
    public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments,IDiagnosticsLogger<DbLoggerCategory.Query> logger)
    {
        //你需要的转换代码,并返回你的SqlExpression
        return null;
    }
}
public class MyMethodCallTranslatorPlugin:IMethodCallTranslatorPlugin
{
    public IEnumerable<IMethodCallTranslator> Translators{get;}
    //坑1:这里注入时不能用SqlServerSqlExpressionFactory,无法解析SqlServerSqlExpressionFactory,只能ISqlExpressionFactory注入后再强转成SqlServerSqlExpressionFactory
    public MyMethodCallTranslatorPlugin(ISqlExpressionFactory sqlExpressionFactory)
    {
        Translators=new List<IMethodCallTranslator>()
        {
            new MyMethodCallTranslator((SqlServerSqlExpressionFactory)sqlExpressionFactory)
        }
    }
}
public class MyDbContextOptionsExtension:IDbContextOptionsExtension
{
    private DbContextOptionsExtensionInfo? _info;
    public virtual void ApplyServices(IServiceCollection services)
    {
        //坑2:必须用new EntityFrameworkRelationalServicesBuilder(services)再添加服务,不能直接用services添加
        new EntityFrameworkRelationalServicesBuilder(services)
            .TryAdd<IMethodCallTranslatorPlugin, MyMethodCallTranslatorPlugin>();
    }
    public virtual DbContextOptionsExtensionInfo Info
        => _info ??= new ExtensionInfo(this);
    public virtual void Validate(IDbContextOptions options)
    {
    }
    private sealed class ExtensionInfo(IDbContextOptionsExtension extension) : DbContextOptionsExtensionInfo(extension)
    {
        public override bool IsDatabaseProvider => false;

        public override int GetServiceProviderHashCode() => 0;

        public override bool ShouldUseSameServiceProvider(DbContextOptionsExtensionInfo other)
            => other is ExtensionInfo;

        public override void PopulateDebugInfo(IDictionary<string, string> debugInfo)
        {
        }

        public override string LogFragment => "";
    }
}
public static class MySqlServerDbContextOptionsBuilder Extensions
{
    //坑3:这里要用具体数据库的...DbContextOptionsBuilder,用DbContextOptionsBuilder也行,但是就无法注入具体的ISqlExpressionFactory
    //关键是SqlServerDbContextOptionsBuilder不是从DbContextOptionsBuilder继承的,看名称似乎是继承的,其实不是
    public static SqlServerDbContextOptionsBuilder Use...(this SqlServerDbContextOptionsBuilder optionsBuilder)
    {
        var coreOptionsBuilder = ((IRelationalDbContextOptionsBuilderInfrastructure)optionsBuilder).OptionsBuilder;

        var extension = coreOptionsBuilder.Options.FindExtension<MyDbContextOptionsExtension>()
            ?? new MyDbContextOptionsExtension();

        ((IDbContextOptionsBuilderInfrastructure)coreOptionsBuilder).AddOrUpdateExtension(extension);

        return optionsBuilder;
    }
}

总结

1. ISqlExpressionFactory

注入时不能用SqlServerSqlExpressionFactory,无法解析SqlServerSqlExpressionFactory,只能ISqlExpressionFactory注入后再强转成SqlServerSqlExpressionFactory

2. EntityFrameworkRelationalServicesBuilder

必须用new EntityFrameworkRelationalServicesBuilder(services)再添加服务,不能直接用services添加

3. DbContextOptionsBuilder

这里要用具体数据库的...DbContextOptionsBuilder,用DbContextOptionsBuilder也行,但是就无法注入具体的ISqlExpressionFactory
关键是SqlServerDbContextOptionsBuilder不是从DbContextOptionsBuilder继承的,看名称似乎是继承的,其实不是