Search code examples
entity-frameworkef-code-firstlinqpad

Prevent LinqPad from querying __MigrationHistory


This is about a performance optimization:

I use LinqPad to access a database using an EF 6 DbContext. The database is created using code first.

When I run a query, I see the correct result, but I see in the "SQL"-tab that LinqPad (and/or EF) emmits SQL to check the migration history:

-- Region Parameters
-- p__linq__0: String [UserQuery]
-- EndRegion
SELECT 
"GroupBy1".A1 AS C1
FROM ( SELECT Count(1) AS A1
    FROM ARIANE_ADMIN."__MigrationHistory" "Extent1"
    WHERE "Extent1"."ContextKey" = :p__linq__0
)  "GroupBy1"
GO

-- Region Parameters
-- p__linq__0: String [UserQuery]
-- EndRegion
SELECT 
"GroupBy1".A1 AS C1
FROM ( SELECT Count(1) AS A1
    FROM "__MigrationHistory" "Extent1"
    WHERE "Extent1"."ContextKey" = :p__linq__0
)  "GroupBy1"
GO

SELECT 
"GroupBy1".A1 AS C1
FROM ( SELECT Count(1) AS A1
    FROM "__MigrationHistory" "Extent1"
)  "GroupBy1"
GO

SELECT 
"Extent1"."Id",
"Extent1"."ModelHash"
FROM "EdmMetadata" "Extent1"
ORDER BY "Extent1"."Id" DESC
FETCH FIRST 1 ROWS ONLY
GO

Only then there is the actual query.

Since I usually access the DB through multiple layers of VPN, the extra queries cost more than a second.

My questions are:

  1. Can I avoid the query to '__MigrationHistory' alltogether?
  2. If not: Is there a way to pass the correct parameter instead of '[UserQuery]', so that the first query returns the correct result?

I connect to an Oracle server using Devart dotconnect for Oracle.


Solution

  • As Steve Greene suggested, you have to set a null initializer. But not for your DbContext. It must be set for the UserQuery-Type that LinqPad dynamically creates.

    It can be done by writing

    Database.SetInitializer<UserQuery>(null);
    

    at the beginning of every LinqPad query.

    A more general approach is to set it in your dll using reflection.

    Add this extension method

    public static class DbContextExtensions
    {
        public static void RemoveLinqpadInitializer(this DbContext context)
        {
            var contextType = context.GetType();
            if (contextType.Name == "UserQuery")
            {
                var setInitializer = typeof(Database).GetMethod(nameof(Database.SetInitializer))?.MakeGenericMethod(contextType);
                setInitializer?.Invoke(null, new object[] {null});
            }
        }
    }
    

    and call it in your DbContext:

    public class MyDbContext : DbContext
    {
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
    
            Database.SetInitializer<MyDbContext>(null); // or any other initializer
            this.RemoveLinqpadInitializer();
        }
    }