8

How can I prevent the use of the parameterless constructor of the generated DbContext?

var dcx = new DataEntities();

The default constructor is generated by the T4 template, and I thus cannot override it in a partial class. I would prefer it not compile, but a runtime error would also be good.

Zev Spitz
  • 13,950
  • 6
  • 64
  • 136

3 Answers3

14

You can modify the template to provide the constructor you want.

  • Open the *.Context.tt file
  • Go to line ~59
  • Change this code.

    public <#=code.Escape(container)#>()
        : base("name=<#=container.Name#>")
    
  • Into the default constructor you want, for example.

    public <#=code.Escape(container)#>(string nameOrConnectionString)
        : base(nameOrConnectionString)
    
  • Save

Yuliam Chandra
  • 14,494
  • 12
  • 52
  • 67
2

You can inherit the DbContext created by the template, define your own constructor, and use the inherited DbContext instead of the one generated by the template.

public class MyModifiedDbContext : TheTemplateGeneratedDbContext
{
   public MyModifiedDbContext() 
   {
       // define your own constructor
   }
}

Or make it private to avoid its use, so you get the error at compile time

public class MyModifiedDbContext : TheTemplateGeneratedDbContext
{
   private MyModifiedDbContext() 
   // ...
}

Use MyModifiedDbContext instead of TheTemplateGeneratedDbContext

JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • This doesn't prevent me from using `new TheTemplateGeneratedDbContext()`. – Zev Spitz Aug 20 '14 at 09:21
  • Of course, but there are many options to "hide" the original generated DbContext. It all depends on the structure of your project files. I suppose you have a monolithic app with everything messed up, and so you don't have control on who, where and when uses this constructor. Stuck to Yuliam Chandra solution or re-organize your code. – JotaBe Aug 20 '14 at 09:28
  • Would you mind elaborating on how I could implement **control on who, where and when uses this constructor**, and what code reorganizations I should consider? – Zev Spitz Aug 20 '14 at 18:55
  • You can apply architectural patterns. It cannot be explained in a few lines. But the solution is mostly based on interfaces. Then you can use DI or an abstract factory. The projects that needs the DbContext uses the DI or the abstract factory, but doesn't know anything about the final implementation. The final implementation of the DI dependency, or the abstract factory is the only one with acces to the implementation of the DbContexts. It0s much better to have the things under control, that to "make a trick" to avoid the developer from doing the wrong thing. – JotaBe Aug 20 '14 at 19:56
1

I gave up waiting for EF Core team to add this as an option. I don't want to make and maintain my own T4 templates for this - that's nuts!

Solution for me was just to run some regex on the generated code as part of a powershell script.

fix-dbcontext.ps1

$filename=$args[0]

# load context file
$content = (Get-Content -Raw $filename) 

[regex] $commentOutConstructorRegex = '(?ms)(?<=: DbContext\s*.*?)(public.*?)(?=\s*public)'
$content = $commentOutConstructorRegex.Replace($content, '// Default constructor removed', 1)

[regex] $removeOnConfiguringRegex = '(?ms)(protected override void OnConfiguring).*?(?=\s*protected)'
$content = $removeOnConfiguringRegex.Replace($content, '// Generated OnConfiguring removed', 1)

[regex] $dateCommentRegex = '(?ms)(?=\s*public partial class)'
$content = $dateCommentRegex.Replace($content, "`r`n`t// Generated " + (Get-Date).ToString() + "`r`n", 1)

$content | Out-File -Encoding UTF8 $filename

This will:

  1. Remove the default constructor
  2. Remove the OnConfiguring method including hardcoded connection string
  3. Add the date in a comment

Just run it with .\fix-dbcontext.ps1 .\MyDBContext.cs.

You probably want to change that last line to context.txt instead of $filename until you're sure it does what you want.

IMPORTANT: This was tested only on EFCore templates, but if you understand my Regexes you should be able to modify it for EntityFramework if it doesn't already work.

Simon_Weaver
  • 140,023
  • 84
  • 646
  • 689