Database.SetInitializer to null not working Entity

2019-01-25 20:04发布

问题:

I have a context class that inherits from an abstract base AuditableDbContext : DbContext. The AuditableDbContext takes two parameters, one for the auditor and one for the context to audit into.

In the inherited class, I have a default parameterless constructor that calls the other constructors with null parameters and then in the final constructor I call Database.SetInitializer<MyDbContext>(null) after calling the base constructor.

The problem is that even when I do this, I still get the db migration calls on the database server when the application starts.

public abstract class AuditableContext : DbContext
{
  public AuditableContext(IAuditor auditor, DbContext auditContext)
  {
    // params can be null resulting in no auditing
    // initialization stuff here...
  }
}

public class MyDbContext : AuditableContext
{
  // DbSets here...

  public MyDbContext() : this(null, null) {}

  public MyDbContext(IAuditor auditor) : this(auditor, null) {}

  public MyDbContext(IAuditor auditor, DbContext auditContext) 
  : base(auditor, auditContext)
  {
    Database.SetInitializer<MyDbContext>(null);
  }
}

The queries I see on the database are the two common migration queries...

SELECT [GroupBy1].[A1] AS [C1]
FROM ( SELECT COUNT(1) AS [A1]
FROM [dbo].[__MigrationHistory] AS [Extent1]
)  AS [GroupBy1]

SELECT TOP (1) 
[Extent1].[Id] AS [Id], 
[Extent1].[ModelHash] AS [ModelHash]
FROM [dbo].[EdmMetadata] AS [Extent1]
ORDER BY [Extent1].[Id] DESC

Any ideas on how to stop Entity Framework from making these queries?

回答1:

You will need to do this in the static constructor or better still PRIOR to instantiating the Context.

static MyDbContext() {
    Database.SetInitializer<MyDbContext>(null);
}


回答2:

Sorry to reply to such an old question, especially one that is marked as answered, but it has plagued me and I wanted to offer a solution regardless.

The problem is that LINQPad creates a subclass of your DbContext class. So when you called Database.SetInitializer<MyDbContext>(null), that will work as long as you are creating an instance of MyDbContext. But by design, LINQPad compiles your code into a class that derives from MyDbContext. If you make MyDbContext sealed, LINQPad won't be able to use it.

The workaround is to use reflection to call Database.SetInitializer in the instance constructor of MyDbContext. This means you're unnecessarily calling it for every instance of the context, but it won't hurt anything. But this allows you to use this.GetType() to get access to the subclass that LINQPad creates and then you can use reflection to call SetInitializer.

Would be nice if a non-generic version of the method was added though.

This Gist has an example of using reflection to call Database.SetInitializer.

var databaseType = typeof( Database );
var setInitializer = databaseType.GetMethod( "SetInitializer", BindingFlags.Static | BindingFlags.Public );

var thisType = GetType( );
var setInitializerT = setInitializer.MakeGenericMethod( thisType );

setInitializerT.Invoke( null, new object[] { null } );