Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Ajout d'un indicateur de requête lors de l'appel d'une fonction table

Je suis tombé sur ceci :

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

Et il semble que vous puissiez faire quelque chose comme ceci :

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

Et enregistrez-le comme ceci (je l'ai fait dans Application_Start de global.asax.cs ):

DbInterception.Add(new HintInterceptor());

Et cela vous permettra de modifier le CommandText . Le seul problème est qu'il est maintenant attaché pour chaque requête du lecteur qui pourrait être un problème car certains d'entre eux pourraient être affectés négativement par cet indice. Je suppose que je peux faire quelque chose avec le contexte pour déterminer si l'indice est approprié ou non, ou pire, je pourrais examiner le CommandText lui-même.

Cela ne semble pas tout à fait la solution la plus élégante ou la plus fine.

Modifier :Depuis le interceptorContext , vous pouvez obtenir les DbContexts , j'ai donc défini une interface qui ressemble à ceci :

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

Et puis créé une classe qui dérive de mon DbContext d'origine (généré par EF) et implémente l'interface ci-dessus. Ensuite, j'ai changé mon intercepteur pour qu'il ressemble à ceci :

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

Maintenant, pour l'utiliser, je crée un contexte en utilisant ma classe dérivée au lieu de l'original, définissez QueryHint à ce que je veux qu'il soit (recompile dans ce cas) et définissez ApplyHint juste avant d'exécuter la commande et de la remettre à false par la suite.

Pour rendre tout cela un peu plus autonome, j'ai fini par définir une interface comme celle-ci :

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

Et étendu mon contexte de base de données comme ceci (vous pouvez, bien sûr, simplement utiliser une classe partielle pour étendre également la classe générée par EF):

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

Et puis, pour rendre la partie allumer, éteindre un peu plus facile à gérer, j'ai défini ceci :

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

Maintenant, pour l'utiliser, je peux faire juste ceci :

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
}

Cela peut être légèrement exagéré et pourrait être développé davantage (par exemple, en utilisant une énumération pour les conseils disponibles au lieu d'une chaîne - ou en sous-classant un recompile indice de requête afin que vous n'ayez pas besoin de spécifier la chaîne recompile à chaque fois et risquer une faute de frappe), mais cela a résolu mon problème immédiat.