sql >> Databasteknik >  >> RDS >> Sqlserver

Lägga till en frågetips när du anropar tabellvärderad funktion

Jag stötte på det här:

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

Och det verkar som att du kan göra något så här:

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

Och registrera det så här (jag gjorde det i Application_Start av global.asax.cs ):

DbInterception.Add(new HintInterceptor());

Och det låter dig ändra CommandText . Det enda problemet är att det nu är bifogat för varje läsarfråga som kan vara ett problem eftersom vissa av dem kan påverkas negativt av den tipsen. Jag antar att jag kan göra något med sammanhanget för att ta reda på om tipset är lämpligt eller inte, eller i värre fall skulle jag kunna undersöka CommandText sig själv.

Verkar inte riktigt vara den mest eleganta eller finkorniga lösningen.

Redigera :Från interceptorContext , kan du hämta DbContexts , så jag definierade ett gränssnitt som ser ut så här:

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

Och skapade sedan en klass som härrör från min ursprungliga DbContext (genererad av EF) och implementerar ovanstående gränssnitt. Sedan ändrade jag min interceptor till att se ut så här:

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

Nu för att använda det skapar jag ett sammanhang med min härledda klass istället för originalet, ställ in QueryHint till vad jag vill att det ska vara (recompile i det här fallet) och ställ in ApplyHint precis innan jag kör kommandot och ställer tillbaka det till false efteråt.

För att göra det hela lite mer självständigt, slutade jag med att definiera ett gränssnitt så här:

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

Och utökade mitt db-kontext så här (du kan naturligtvis bara använda en partiell klass för att utöka den EF-genererade klassen också):

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

Och sedan, för att göra start- och avstängningsdelen lite lättare att hantera, definierade jag detta:

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

Nu för att använda det kan jag göra just detta:

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
}

Detta kanske är något överdrivet och skulle kunna utvecklas ytterligare (till exempel genom att använda en enum för tillgängliga tips istället för en sträng - eller underklassa en recompile frågetips så att du inte behöver ange strängen recompile varje gång och riskerar ett stavfel), men det löste mitt omedelbara problem.



  1. MySQL tar bort några främmande nycklar

  2. Jämförelse av databaskolumntyper i MySQL, PostgreSQL och SQLite? (Cross-mapping)

  3. Hur man hittar maximala värden i rader

  4. Anpassade triggerbaserade uppgraderingar för PostgreSQL