Entity Framework initialisation best practices - c#

I wish to ensure Entity Framework never overwrites or tries to create the database I am connecting to. It is an established database previously accessed by ASP website (visual basic script flavour). I've seen the convention where you pass "name=" into the base constructor like so...
//example 1
public class SchoolDBContext: DbContext
{
public SchoolDBContext() : base("name=SchoolDBConnectionString")
{
}
}
BUT I'd prefer to NOT have it HARDCODED (like the above), so perhaps...
//example 2
public SchoolDBContext(string ConnectionString) : base("name=" + ConnectionString) {
}
BUT I'd also like to be able to bug out if the string is empty...
//example 3
public SchoolDBContext(string ConnectionString) : {
if (string.IsNullOrWhitespace(ConnectionString) throw Exception("empty connection string");
base("name=" + ConnectionString);
}
Question 1: I'm unsure if the third bit of code does the same job as the second, does it? As the third example may call the parameterless construction first before calling base with the "name="
Question 2: Is there options available in the constructor that can be used to configure EntityFramework more robustly?
I'm Using EF 6

If you dont want EF to overwrite och create a new database every time you need to add the createinitializer class.
public class CreateInitializer : CreateDatabaseIfNotExists<SchoolDBContext>{}

Question 1:
Im not sure either. I need to admit I never saw something like that in examples. May you tell us/me your documentation source or how you came up with that Idea?
Question 2:
If you wan't a independence constructor, how about you try this?
public SchoolDBContext()
: base(ConnectionString == null ? "name=SchoolDBConnectionString" : WhateverYouDoIfItsWrong)
{
// Your code here! Lucky you
}

Have a look at the DbMigrationsConfiguration.
You can create a new class SchoolDbContextConfiguration-class which inherrit from it and set AutomaticMigrationsEnabled to false.
internal sealed class Configuration : DbMigrationsConfiguration<SchoolDBContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
}
}
And in your SchoolDbContext initialize as follows:
public SchoolDBContext(string ConnectionString) : base("name=" + ConnectionString) {
var init = new MigrateDatabaseToLatestVersion<SchoolDBContext, SchoolDbContextConfiguration>(true);
Database.SetInitializer(init);
}

Related

How to create a DbContext instance of the specified database type

I know that the default return here is the SQL Server database type, but I need the MySQL database type, the problem is to create a DbContext instance of the specified database type?
Of course, I know that it can also be created by specifying the connectionName, but the database connection string is encrypted and the string needs to be decrypted
The pseudo code is as follows:
public partial class MyDbContext : DbContext
{
static string mysqlConn = ReadConnectionString(); //Get the encrypted MySQL connection string
public MyDbContext() : base(mysqlConn)
{
// Even if I want to modify the connection string in this way, nor will it throw a connection string malformed exception
Database.Connection.ConnectionString = DecryptConnectionString(mysqlConn);
}
}
Ok, it's about what I expected, few of my questions can be answered.
Although I am not too familiar with EntityFramework, by looking at the source code of DbContext, I can almost certainly determine that this is a design flaw, it lacks a constructor like this:
Public DbContext(string connectionString, string providerName)
I had same problem and found .Net framework 4.5 needs additional attribute on DbContext class to use MySql as below
[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class MySqlContext : DbContext
{
...
}

C# .NET Entity Framework multi-tenant best practice

Consider the following code segment:
public class DatabaseContext : DbContext
{
public DatabaseContext(String connectionString) : base(connectionString)
{
}
}
public class ContextNameDatabaseContext : DatabaseContext
{
public ContextNameDatabaseContext(String connectionString) : base(connectionString)
{
}
}
Would one say it is best practice when building the back-end for a multi-tenant solution where each client has its own database and maintain the data state until a user logs out / off?
Developer using these classes in this instance will need to be aware and careful as to when and how the classes are being used where the 'DatabaseContext' class acts as a base to the 'ContextNameDatabaseContext' class.
Please advise on any thoughts or suggestions.
One approach is to keep all the database connection strings as parameters in the database. However you have to assure that its encrypted.
Then at your DB layer you can pass the connection as parameter in plain text after decrypting and constructing your connection string accordingly:
public class MyDatabase: DbContext
{
public MyDatabase(string connString)
{
this.Database.Connection.ConnectionString = connString;
}
public DbSet<Order> Orders{ get; set; }
}
You can also use IOptions if you are using .NET Core to inject the connection string as a dependency.

EF6 change database create strategy

I have an application where I want to use the FILESTREAM feature for storing blobs. I know that EF6 does not support FILESTREAM, so I will manage file and image handling by myself. However, I have to write my own initialize code to add a FILEGROUP and FILE to my Database and:
public class CustomDbInitializer : CreateDatabaseIfNotExists<DatenbankContext>
{
public override void InitializeDatabase(DatenbankContext context)
{
base.InitializeDatabase(context);
SqlConnectionStringBuilder b = new SqlConnectionStringBuilder(context.Database.Connection.ConnectionString);
context.Database.ExecuteSqlCommand(TransactionalBehavior.DoNotEnsureTransaction,"ALTER DATABASE "+ b.InitialCatalog + " ADD FILEGROUP GRP CONTAINS FILESTREAM");
//more sql commands
}
}
Then, I call manually the function InitializeDatabase(context)
new CustomDbInitializer().InitializeDatabase(context);
However, I find this a bit clunky and counter-intuitive. I know that I can set an initializer for the context in the constructor, but this does not work the way I want:
public class DatenbankContext : DbContext
{
public DatenbankContext()
:base("name=name")
{
Database.SetInitializer(new CustomDbInitializer());
}
}
Basically, I want the call
new DatenbankContext() // or
context.Database.CreateIfNotExists()
to initialize my Database with my custom strategy in an intuitive way. How can this be done?
Inside your custom initializer add:
if (!context.Database.Exists())
{
context.Database.Create();
}
// Do next steps
Call your initializer inside a static constructor. This insures it only runs once:
public class DatenbankContext : DbContext
{
static DatenbankContext()
{
Database.SetInitializer(new CustomDbInitializer());
}
}
See here for more on custom initializers. You probably don't want to inherit from CreateDatabaseIfNotExists if you want control over the process. See the example in link.

Entity Framework Constructor Injection in Asp.net Core

I'm using Entity Framework in ASP.net Core, I have many classes where I am using an instance of the DbContext to interact with the database, I'm using constructor injection in every class and controller but I feel like a trained monkey repeating that code all the time, maybe I'm doing this the wrong way and there are better ways to do this. I'm feeling tired to write again and again the same code for every controller and every class I'm using an instance of DbContext..
Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<DBConnection> Configuration.GetSection("ConnectionStrings"));
}
That code is fine, no problem at all, but now: Do I need to repeat the code below for every class and controller?? I know I have not read a lot yet about services and that I might be losing something obvious, I'm just copying the constructors, but in some classes where I need instances I need to add a field named _connectionAccessor of type IOptions<DBConnection>:
public FirstController(IOptions<DBConnection> connectionsAccessor)
{
_context = new DataContext(connectionsAccessor);
_connectionAccessor = connectionsAccessor;
}
public EmailController(IOptions<DBConnection> connectionsAccessor)
{
this.ctx = new DataContext(connectionsAccessor);
_connectionAccessor = connectionsAccessor;
}
public MyRepository(IOptions<DBConnection> connectionsAccessor)
{
_context = new DataContext(connectionsAccessor);
_connectionAccessor = connectionsAccessor;
}
And like that for every controller and class, and I have a lot of classes and controllers, is this the only way?
Oh this is my DbContext class:
public class DataContext : DbContext
{
public DataContext(IOptions<DBConnection> connectionsAccessor)
{
this.Database.Connection.ConnectionString = connectionsAccessor.Value.MySQLContext;
}

Creating a DbContext with custom constructor with injected parameter in Entity Framework

I am working on a code first database, but when I try to do "Update-Database" I get the following error.
The target context 'AllMid.DL.Repository.Implementation.AllMidContext' is not constructible.
Add a default constructor or provide an implementation of IDbContextFactory.
Now it is apparent to me that the problem is that I don't have a default constructor or a an implementation of the IDbContextFactory interface, but in the sample project I am using I am seeing this done without either. Does anyone know how to go about this?
I currently have a DbContext resembling this.
internal class AllMidContext : DbContext, IAllMidContext
{
public DbSet<TreeEntity> Tree { get; set; }
public AllMidContext(IConfigurationAccess configAccess) : base(configAccess.GetDefaultConnectionString())
{
}
}
The configAccess should be being injected by structure map.
and a DataContextAccess class like this
internal class DataContextAccess : IDataContextAccess
{
private readonly IConfigurationAccess _configAccess;
public DataContextAccess(IConfigurationAccess configAccess)
{
_configAccess = configAccess;
}
public IAllMidContext GetAllMidContext()
{
return new AllMidContext(_configAccess);
}
}
Now the question is is there a way to do this without a default constructor or a factory? My dependency injection will always input the parameter so how can I get EF to use my custom constructor?
I believe that update-database is looking for a constructor with no input. what you can do is to write a constructor with no inputs and do your injection in its body.

Categories