sql >> データベース >  >> RDS >> Sqlserver

テーブル値関数を呼び出すときにクエリヒントを追加する

    私はこれに出くわしました:

    https://entityframework.codeplex.com/wikipage?title=Interception

    そして、あなたはこのようなことをすることができるようです:

    public class HintInterceptor : DbCommandInterceptor
    {
        public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            command.CommandText += " option (recompile)";
            base.ReaderExecuting(command, interceptionContext);
        }
    }
    

    そして、このように登録します(Application_Startで登録しました global.asax.csの ):

    DbInterception.Add(new HintInterceptor());
    

    また、CommandTextを変更できます 。唯一の問題は、すべてに接続されていることです。 それらのいくつかはそのヒントによって悪影響を受ける可能性があるため、問題になる可能性のあるリーダークエリ。ヒントが適切かどうかを判断するためにコンテキストを使って何かを行うことができると思います。最悪の場合、CommandTextを調べることができます。

    最もエレガントできめの細かいソリューションではないようです。

    編集interceptorContextから 、DbContextsを取得できます 、それで私は次のようなインターフェースを定義しました:

    public interface IQueryHintContext
    {
        string QueryHint { get; set; }
        bool ApplyHint { get; set; }
    }
    

    次に、元のDbContext(EFによって生成された)から派生し、上記のインターフェイスを実装するクラスを作成しました。次に、インターセプターを次のように変更しました:

    public class HintInterceptor : DbCommandInterceptor
    {
        public override void ReaderExecuting(System.Data.Common.DbCommand command, DbCommandInterceptionContext<System.Data.Common.DbDataReader> interceptionContext)
        {
            if (interceptionContext.DbContexts.Any(db => db is Dal.IQueryHintContext))
            {
                var ctx = interceptionContext.DbContexts.First(db => db is Dal.IQueryHintContext) as Dal.IQueryHintContext;
                if (ctx.ApplyHint)
                {
                    command.CommandText += string.Format(" option ({0})", ctx.QueryHint);
                }
            }
            base.ReaderExecuting(command, interceptionContext);
        }
    }
    

    これを使用するために、元のクラスの代わりに派生クラスを使用してコンテキストを作成し、QueryHintを設定します。 私が望むものに(recompile この場合)、ApplyHintを設定します コマンドを実行する直前に、コマンドをfalseに戻します。

    これをもう少し自己完結型にするために、私は次のようなインターフェースを定義することになりました:

    public interface IQueryHintContext
    {
        string QueryHint { get; set; }
        bool ApplyHint { get; set; }
    }
    

    そして、このようにデータベースコンテキストを拡張しました(もちろん、部分クラスを使用してEFで生成されたクラスを拡張することもできます):

    public class MyEntities_Ext : MyEntities, IQueryHintContext
    {
        public string QueryHint { get; set; }
        public bool ApplyHint { get; set; }
    }
    

    次に、ターンオンとターンオフの部分を少し扱いやすくするために、次のように定義しました。

    public class HintScope : IDisposable
    {
        public IQueryHintContext Context { get; private set; }
        public void Dispose()
        {
            Context.ApplyHint = false;
        }
    
        public HintScope(IQueryHintContext context, string hint)
        {
            Context = context;
            Context.ApplyHint = true;
            Context.QueryHint = hint;
        }
    }
    

    今それを使用するために、私はこれを行うことができます:

    using (var ctx = new MyEntities_Ext()) 
    {
        // any code that didn't need the query hint
        // ....
        // Now we want the query hint
        using (var qh = new HintScope(ctx, "recompile"))
        {
            // query that needs the recompile hint
        }
        // back to non-hint code
    }
    

    これは少しやり過ぎかもしれませんし、さらに発展させることができます(たとえば、文字列の代わりに利用可能なヒントの列挙型を使用するか、recompileをサブクラス化する 文字列recompileを指定する必要がないようにヒントを照会します 毎回、タイプミスのリスクがあります)が、それは私の当面の問題を解決しました。



    1. Node.js MSSQL tedius ConnectionError:localhost:1433への接続に失敗しました-ECONNREFUSEDに接続します

    2. SQLServer-Windows認証で接続します

    3. WEEK()の例– MySQL

    4. シリアル化された配列内のmysqlselectクエリ