-
Notifications
You must be signed in to change notification settings - Fork 226
ConnectionString
Settings.ConnectionString is the one setting you cannot leave alone. Get it right and everything else
follows.
New users trip over this constantly, so it is worth being explicit. There are two settings with similar names, used at completely different times.
| Setting | Used by | When | Must be |
|---|---|---|---|
Settings.ConnectionString |
The generator | Design time, when you save Database.tt
|
A full, working connection string |
Settings.ConnectionStringName |
Your application | Run time | A key that exists in appsettings.json / app.config / web.config
|
The generator never reads connection strings out of your config files. You have to hand it the whole thing.
// Used to reverse engineer your database when you save this file
Settings.ConnectionString = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True;Encrypt=false;TrustServerCertificate=true";
// Just a key. Placed into the generated DbContext constructor. Never used by the generator.
Settings.ConnectionStringName = "MyDbContext";Depending on Settings.OnConfiguration, your design-time connection string may also
be copied into the generated DbContext.OnConfiguring(). If you would rather it did not end up in source
control, use OnConfiguration.Omit or OnConfiguration.Configuration and configure the provider yourself.
That is the usual choice for anything deployed.
Settings.DatabaseType = DatabaseType.SqlServer;
Settings.TemplateType = TemplateType.EfCore10;
Settings.GeneratorType = GeneratorType.EfCore;
Settings.ConnectionString = "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True;MultipleActiveResultSets=True;Encrypt=false;TrustServerCertificate=true";Other shapes you will meet:
// Named instance, Windows authentication
"Data Source=.\\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True;Encrypt=false;TrustServerCertificate=true"
// LocalDB, the one Visual Studio installs
"Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=Northwind;Integrated Security=True"
// SQL authentication
"Data Source=sql01.example.com,1433;Initial Catalog=Northwind;User ID=readonly_user;Password=***;Encrypt=True"
// Azure SQL Database
"Server=tcp:myserver.database.windows.net,1433;Initial Catalog=Northwind;User ID=readonly_user;Password=***;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30"
// Azure SQL with Entra ID (formerly Azure AD)
"Server=tcp:myserver.database.windows.net,1433;Initial Catalog=Northwind;Authentication=Active Directory Default;Encrypt=True"Why Encrypt=false;TrustServerCertificate=true? Microsoft.Data.SqlClient encrypts by default from
version 4.0 onwards. A local development SQL Server usually has a self-signed certificate your machine does not
trust, and without one of those two settings you get:
A connection was successfully established with the server, but then an error occurred during the login process.
Do not carry TrustServerCertificate=true into production. There, install a real certificate and use
Encrypt=True on its own.
MultipleActiveResultSets=True is only needed if you turn on lazy loading.
More detail, including what the generator can read: SQL Server
Settings.DatabaseType = DatabaseType.PostgreSQL;
Settings.TemplateType = TemplateType.EfCore10;
Settings.GeneratorType = GeneratorType.EfCore;
Settings.ConnectionString = "Server=127.0.0.1;Port=5432;Database=Northwind;User Id=testuser;Password=***;";Other shapes:
// Host= is a synonym for Server=, Username= for User Id=. Npgsql accepts both.
"Host=localhost;Port=5432;Database=Northwind;Username=testuser;Password=***"
// TLS to a managed instance (AWS RDS, Azure Database for PostgreSQL, Supabase, Neon, ...)
"Host=db.example.com;Port=5432;Database=Northwind;Username=readonly_user;Password=***;SSL Mode=Require;Trust Server Certificate=true"
// Through pgbouncer, where server-side pooling is already doing the job
"Host=db.example.com;Port=6432;Database=Northwind;Username=readonly_user;Password=***;Pooling=false"The default schema is public, and every schema your user can see is read in one pass.
Watch the case. PostgreSQL folds unquoted identifiers to lower case, so CREATE TABLE MyTable really
creates mytable. That matters for Filtering, because filters match the database name, not the
generated class name.
More detail: PostgreSQL
Settings.DatabaseType = DatabaseType.MySql;
Settings.TemplateType = TemplateType.EfCore10;
Settings.GeneratorType = GeneratorType.EfCore;
Settings.OnConfiguration = OnConfiguration.Omit; // see below
Settings.ConnectionString = "Server=localhost;Port=3306;Database=Northwind;User Id=root;Password=***;";Other shapes:
// Uid/Pwd are accepted as synonyms for User Id/Password
"Server=localhost;Port=3306;Database=Northwind;Uid=readonly_user;Pwd=***;"
// TLS to a managed instance (AWS RDS, Azure Database for MySQL, PlanetScale, ...)
"Server=db.example.com;Port=3306;Database=Northwind;User Id=readonly_user;Password=***;SslMode=Required;"
// Unix socket
"Server=/var/run/mysqld/mysqld.sock;Database=Northwind;User Id=readonly_user;Password=***;"Database= is not optional. In MySQL a database is a schema. Whatever you name here is the only schema
the generator reads, and tables in other databases on the same server are invisible to it, including through
a foreign key that points at them.
Set OnConfiguration.Omit for MySQL. The EF Core provider is Pomelo, whose UseMySql() takes a mandatory
ServerVersion argument that the generator does not emit. Configure it where you register the context:
var cs = builder.Configuration.GetConnectionString("MyDbContext");
builder.Services.AddDbContext<MyDbContext>(o => o.UseMySql(cs, ServerVersion.AutoDetect(cs)));More detail: MySQL
Settings.DatabaseType = DatabaseType.Oracle;
Settings.TemplateType = TemplateType.EfCore10;
Settings.GeneratorType = GeneratorType.EfCore;
Settings.ConnectionString = "User Id=northwind;Password=***;Data Source=localhost:1521/pdb1;";Other shapes:
// Easy Connect: host:port/service_name. Simplest, no tnsnames.ora needed.
"User Id=northwind;Password=***;Data Source=db.example.com:1521/ORCLPDB1;"
// TNS alias, resolved from tnsnames.ora in the folder named by the TNS_ADMIN environment variable
"User Id=northwind;Password=***;Data Source=MYALIAS;"
// Full descriptor inline
"User Id=northwind;Password=***;Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=db.example.com)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)));"
// Autonomous Database with a wallet. Point TNS_ADMIN at the unzipped wallet folder first.
"User Id=northwind;Password=***;Data Source=mydb_high;"In Oracle the user is the schema. There is no Database= or Schema= part. The generator reads the
current schema of whoever you connect as, and only that one schema, so connect as the owner of the schema you
want to reverse engineer. Connecting as SYSTEM and expecting to see NORTHWIND will not work.
Oracle folds unquoted identifiers to upper case, so your filters need to match ORDER_LINE_ITEM, not
Order_Line_Item.
More detail: Oracle
Settings.DatabaseType = DatabaseType.SQLite;
Settings.TemplateType = TemplateType.EfCore10;
Settings.GeneratorType = GeneratorType.EfCore;
Settings.ConnectionString = @"Data Source=C:\data\Northwind.db";Other shapes:
// Relative to your .tt file. Settings.Root is the folder containing it.
"Data Source=" + Path.Combine(Settings.Root, "Northwind.db")
// Read-only. A sensible default for a generator.
@"Data Source=C:\data\Northwind.db;Mode=ReadOnly"
// Encrypted with SQLCipher or SQLite SEE
@"Data Source=C:\data\Northwind.db;Password=***"Use an absolute path, or build one from Settings.Root. A relative Data Source resolves against the
process working directory, which is not where you think it is when the generator runs. SQLite then cheerfully
creates a new, empty database there, and you get no tables and no error. If your generated file comes out
empty, check the path first.
More detail: SQLite
It only ever reads, with one exception noted below. Give it the least it needs.
| Database | Minimum |
|---|---|
| SQL Server |
db_datareader plus VIEW DEFINITION on the database. db_ddladmin also works, and is the blunt instrument if you are stuck |
| PostgreSQL |
CONNECT on the database and USAGE on the schemas you want. The catalogue is readable by default |
| MySQL |
SELECT on the database, which is what filters information_schema for you |
| Oracle |
CREATE SESSION, plus visibility of the objects. Connecting as the schema owner is simplest |
| SQLite | Read access to the file |
The exception. On SQL Server, stored procedure return models are discovered by executing each procedure
with SET FMTONLY ON, which returns column metadata without running the body. That needs EXECUTE permission
on the procedures. If you cannot get it, turn the whole thing off:
FilterSettings.IncludeStoredProcedures = false;
FilterSettings.IncludeTableValuedFunctions = false;
FilterSettings.IncludeScalarValuedFunctions = false;That is also the single biggest speed-up available on a large database.
Database.tt is a source file. Anything you type into it gets committed. Three ways round that, in increasing
order of effort.
Click the Start button, type env, press Enter, and click Environment Variables at the bottom right of the
dialog. Add a User variable, for example EFRPG_NORTHWIND.

Notice that you don't add quotes around the connection string in the environment variable.
And to pick that up in the <database>.tt file, use:
Settings.ConnectionString = Environment.GetEnvironmentVariable("EFRPG_NORTHWIND", EnvironmentVariableTarget.User);Restart Visual Studio after adding or changing it. Visual Studio caches the environment it was started with, so a new variable is invisible to a session that was already running.
Settings.ConnectionString = File.ReadAllText(
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".efrpg", "northwind.txt")).Trim();Database.tt is ordinary C#, so it can parse the file itself. There is no JSON library available inside T4, so
a small regex is the pragmatic answer:
var appsettings = File.ReadAllText(Path.Combine(Settings.Root, "..", "appsettings.Development.json"));
Settings.ConnectionString = System.Text.RegularExpressions.Regex
.Match(appsettings, "\"MyDbContext\"\\s*:\\s*\"([^\"]+)\"").Groups[1].Value;Whichever you choose, also set Settings.OnConfiguration = OnConfiguration.Omit; so the string is not copied
into the generated .cs either.
Worth knowing, because it is a real improvement over v3. The template passes your connection string to the
efrpg tool over stdin, never as a command-line argument. Command-line arguments are captured by process
listings and, more to the point, by command-line audit logging (Sysmon event 1, EDR telemetry, ETW) which
forwards them to a SIEM and to everybody who can read it. Passing it over stdin stops a password in your .tt
file from spreading into your organisation's security logging.
--connection and --connection-base64 still exist on the tool for interactive and CI use, and are documented
as visible in process listings. Base64 is transport encoding to survive shell quoting, not protection.
The fastest way to tell "my connection string is wrong" from "my settings are wrong" is to bypass the template entirely and run the tool by hand:
efrpg --database SqlServer --connection "Data Source=(local);Initial Catalog=Northwind;Integrated Security=True;Encrypt=false;TrustServerCertificate=true"
A wall of XML means your connection string and permissions are fine, and the problem is in Database.tt. An
error on stderr means you have found it in one step.
For anything with a real password, prefer stdin:
'<Secrets><Connection>Host=localhost;Database=Northwind;Username=testuser;Password=***</Connection></Secrets>' |
efrpg -d PostgreSQL --secrets-stdin > schema.xmlSee Upgrading from v3 to v4 for the full tool command line.
-
Settings.OnConfiguration - what ends up in your generated
DbContext - SQL Server | PostgreSQL | MySQL | Oracle | SQLite
- Settings Reference
- connectionstrings.com - far more variations than are listed here
- Settings A-Z - every setting, with a page each
- Common Settings Types Explained
- Settings Callbacks
- Settings runtime values and helpers
- Filtering
- Full Control Over the Generated Code
- Enum Generation from Table Data
- Owned Entities
- JSON column support
- Global Query Filters
- Extended Property Names Feature
- Partial Properties
- File-Scoped Namespaces
- Data Annotations
- Spatial Types
- HierarchyId
- RowVersion and TimeStamp columns
- Lazy Loading
- Stored proc result sets
- Custom File-Based Templates
- Extra entities via partial classes
- INotifyPropertyChanged
- Syntax colour for T4