sql >> Base de Datos >  >> RDS >> Sqlserver

Agregar una sugerencia de consulta al llamar a la función con valores de tabla

Me encontré con esto:

https://entityframework.codeplex.com/wikipage?title=Intercepción

Y parece que puedes hacer algo como esto:

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

Y regístrelo así (lo hice en Application_Start de global.asax.cs ):

DbInterception.Add(new HintInterceptor());

Y te permitirá modificar el CommandText . El único problema es que ahora está adjunto para cada consulta del lector, lo que podría ser un problema, ya que algunos de ellos podrían verse afectados negativamente por esa sugerencia. Supongo que puedo hacer algo con el contexto para averiguar si la sugerencia es apropiada o no, o en el peor de los casos podría examinar el CommandText mismo.

No parece la solución más elegante o detallada.

Editar :Del interceptorContext , puede obtener los DbContexts , así que definí una interfaz que se ve así:

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

Y luego creé una clase que se deriva de mi DbContext original (generado por EF) e implementa la interfaz anterior. Luego cambié mi interceptor para que se vea así:

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

Ahora, para usarlo, creo un contexto usando mi clase derivada en lugar del original, establezco QueryHint a lo que yo quiera que sea (recompile en este caso) y establecer ApplyHint justo antes de ejecutar el comando y volver a configurarlo como falso después.

Para hacer todo esto un poco más autónomo, terminé definiendo una interfaz como esta:

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

Y extendí mi contexto de base de datos de esta manera (por supuesto, también podría usar una clase parcial para extender la clase generada por EF):

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

Y luego, para que la parte de encendido y apagado sea un poco más fácil de manejar, definí esto:

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

Ahora, para usarlo, solo puedo hacer esto:

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
}

Esto puede ser un poco exagerado y podría desarrollarse aún más (por ejemplo, usando una enumeración para las sugerencias disponibles en lugar de una cadena, o subclasificando una recompile sugerencia de consulta para que no necesite especificar la cadena recompile cada vez y correr el riesgo de un error tipográfico), pero resolvió mi problema inmediato.