I have a C# application using Entity Framework and ObjectContext. I wish to implement connection resiliency like mentioned here: https://msdn.microsoft.com/en-us/library/dn456835(v=vs.113).aspx
How do I assign the DbConfiguration class to the ObjectContext (i.e. how do I 'tell' the ObjectContext to use the configuration)?
You can provide a configuration class which is extended from DbMigrationsConfiguration<YourContext>
internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "YourContext_";
}
protected override void Seed(YourContext context)
{
//Migrate your data
}
}
Related
The IDbCommandInterceptor interface is not very well documented. And I've only found a few scarce tutorials on it:
http://www.entityframeworktutorial.net/entityframework6/database-command-interception.aspx
https://msdn.microsoft.com/en-us/data/jj556606%28v=vs.113%29.aspx
https://entityframework.codeplex.com/wikipage?title=Interception
https://www.tutorialspoint.com/entity_framework/entity_framework_command_interception.htm
https://msdn.microsoft.com/en-us/data/dn469464%28v=vs.113%29.aspx
And a few SO questions:
Entity Framework 6 - Timing queries
Getting DbContext from implementation of IDbCommandInterceptor
These are the suggestions on hooking I've found:
1 - The static DbInterception class:
DbInterception.Add(new MyCommandInterceptor());
2 - Doing the above suggestion in a DbConfiguration class
public class MyDBConfiguration : DbConfiguration {
public MyDBConfiguration() {
DbInterception.Add(new MyCommandInterceptor());
}
}
3 - Using the config file:
<entityFramework>
<interceptors>
<interceptor type="EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/>
</interceptors>
</entityFramework>
Although I couldn't figure out how to hook the DbConfiguration class to the DbContext, and neither what to put in the type part of the config method. Another example I found seemed to suggest that you write the namespace of a logger:
type="System.Data.Entity.Infrastructure.Interception.DatabaseLogger, EntityFramework"
I noted that DataBaseLogger implements IDisposable, IDbConfigurationInterceptor and
IDbInterceptor. IDbCommandInterceptor also implements IDbInterceptor, so I tried (without success) to format it like this:
type="DataLayer.Logging.MyCommandInterceptor, DataLayer"
And when I called the static DbInterception class directly, it added another interceptor every call. So my quick and dirty solution was to utilize static constructors:
//This partial class is a seperate file from the Entity Framework auto-generated class,
//to allow dynamic connection strings
public partial class MyDbContext // : DbContext
{
public Guid RequestGUID { get; private set; }
public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
{
DbContextListeningInitializer.EnsureListenersAdded();
RequestGUID = Guid.NewGuid();
//Database.Log = m => System.Diagnostics.Debug.Write(m);
}
private static class DbContextListeningInitializer
{
static DbContextListeningInitializer() //Threadsafe
{
DbInterception.Add(new MyCommandInterceptor());
}
//When this method is called, the static ctor is called the first time only
internal static void EnsureListenersAdded() { }
}
}
But what are the proper/intended ways to do it?
I figured out that my DbContext class just needed to have the DbConfigurationType attribute, to attach a configuration at runtime:
[DbConfigurationType(typeof(MyDBConfiguration))]
public partial class MyDbContext // : DbContext
{
public MyDbContext(string nameOrConnectionString) : base(nameOrConnectionString)
{ }
}
public class MyDBConfiguration : DbConfiguration {
public MyDBConfiguration() {
this.AddInterceptor(new MyCommandInterceptor());
}
}
The docs suggests that you can just put it in Application_Start:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
DbInterception.Add(new SchoolInterceptorTransientErrors());
DbInterception.Add(new SchoolInterceptorLogging());
}
The important part is that it only get's called once.
How to use an internal DbContext?
I wonder how can I hide the DbContext object so that other libraries of my project not directly access.
I put my DbContext as internal in the library, and apparently should work, however when I run the application, the following error appears:
The target context 'Context' is not constructible. Add a default constructor or Provide an Implementation of IDbContextFactory
Could someone help me?
My implementation of data layer is:
[DbConfigurationType(typeof (ConfigContext))]
internal class Context : DbContext
{
internal Context()
: base(ConfigDataBase.GetSqlServerString(ConfigZnfce.Instance.SqlServerInstance))
{
}
//More code below
}
public class ConfigContext: DbConfiguration
{
public ConfigContext()
{
SetDefaultConnectionFactory(new System.Data.Entity.Infrastructure.LocalDbConnectionFactory("v11.0"));
SetProviderServices("System.Data.SqlClient", System.Data.Entity.SqlServer.SqlProviderServices.Instance);
SetDatabaseInitializer(new CreateDatabaseIfNotExists<Context>());
SetDatabaseInitializer(new MigrateDatabaseToLatestVersion<Context, Configuration>());
}
}
I want all the other libraries are required to go through a unit of work and repositories in order to do any operation with the database
[SOLVED]
I left the Context class as "internal" and set the constructor as "public" as in the code below:
[DbConfigurationType(typeof (ConfigContext))]
internal class Context : DbContext
{
public Context()
: base(ConfigDataBase.GetSqlServerString(ConfigZnfce.Instance.SqlServerInstance))
{
}
//More code below
}
The virtual DBSet<> properties on the DbContext class must be public (as you found out in your solution.
If you're using TT templates, you can make this happen by changing the DbSet(EntitySet entitySet) function. Notice that the term public replaces the original {0} parameter in the string format.
public string DbSet(EntitySet entitySet) {
return string.Format(
CultureInfo.InvariantCulture,
"public virtual DbSet<{0}> {1} {{ get; set; }}",
_typeMapper.GetTypeName(entitySet.ElementType),
_code.Escape(entitySet));
}
Now, you can have an internal DbContext, internal objects, and still have the public automatic properties so EF can do its data-binding.
I am starting a vNext project, and I'm having some issues kicking it off the ground. I have added a table to the ApplicationDbContext class, and it successfully created the table in the db (which in my case is in Azure). However, I can't seem to correctly instantiate a dbContext to use in my Controllers.
In my experience with previous ASP.NET EF projects, I could instantiate the ApplicationDbContext class without passing it any parameters, but in the case of vNext however, it seems to expect a number of things (IServiceProvider, and IOptionsAccessor<DbContextOptions>). I have tried creating a parameter-less constructor, but the App breaks due to not knowing what connection strings to use. My code is below -- as you see in the OnConfiguring(DbContextOptions options) override, I force the connection string in via the DbContextOptions, but that's obviously not ideal, and I feel like I'm just not understanding where those two IServiceProvider, and IOptionsAccessor parameters need to come from.
Thanks for any help!
namespace Project.Models
{
// Add profile data for application users by adding properties to the ApplicationUser class
public class ApplicationUser : IdentityUser
{
public string CompanyName { get; set; }
}
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
private static bool _created = false;
public DbSet<Business> Businesses { get; set; }
public ApplicationDbContext()
: base()
{
if (!_created)
{
Database.EnsureCreated();
_created = true;
}
}
protected override void OnConfiguring(DbContextOptions options)
{
var configuration = new Configuration();
configuration.AddJsonFile("config.json");
configuration.AddEnvironmentVariables();
options.UseSqlServer(configuration.Get("Data:DefaultConnection:ConnectionString"));
}
public ApplicationDbContext(IServiceProvider serviceProvider, IOptionsAccessor<DbContextOptions> optionsAccessor)
: base(serviceProvider, optionsAccessor.Options)
{
// Create the database and schema if it doesn't exist
// This is a temporary workaround to create database until Entity Framework database migrations
// are supported in ASP.NET vNext
if (!_created)
{
Database.EnsureCreated();
_created = true;
}
}
}
}
IServiveProvider and IOptionAccessor are injected by the Dependency Injection
the ASP.Net Core DI has limitation, you cannot have more than one constructor.
Read this: http://blogs.msdn.com/b/webdev/archive/2014/06/17/dependency-injection-in-asp-net-vnext.aspx
I am having a scenario where the AutomaticMigrationDataLossAllowed property of my Configuration class is not working in Entity Framework 6.
I set both the required properties to true, but yet I receive an update exception which states that potential data loss could occur. Ironically, it advices me to set the properties to true that I have already set to true.
Here's how I instantiate my model container (context).
Database.SetInitializer(new ModelInitializer());
Entities = new ModelContainer();
Here's the relevant part of my ModelInitializer class.
internal class ModelInitializer : IDatabaseInitializer<ModelContainer>
{
private static bool _usedBefore;
public void InitializeDatabase(ModelContainer context)
{
...
var migrateInitializer = new MigrateDatabaseToLatestVersion<ModelContainer, Configuration>();
migrateInitializer.InitializeDatabase(context);
}
}
And finally, here's my Configuration class.
internal sealed class Configuration : DbMigrationsConfiguration<ModelContainer>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
protected override void Seed(ModelContainer context)
{
}
}
My ModelContainer class (the context) basically just has a few properties and classes in it, so I don't think that's relevant to the problem. Here's the declaration though.
internal class ModelContainer : DbContext
{
...
}
Have you tried using the '-Force' parameter in the package manager console?
E.g.
Update-Database -Force -Verbose
Are you using separate library for data access??
if yes then you need to provide its name when running query:
Add-Migration -StartUpProjectName "Your DAL Project" MyNewMigration
Update-Database -StartUpProjectName "Your DAL Project" -Verbose
I'm trying to use the interface IPluralizationService to customize the pluralization of my entities without success!
Necessary that all entities are pluralized using the Inflector library.
Attempts
class Config : DbConfiguration
{
public Config()
{
SetPluralizationService(new CustomPluralization());
}
}
class CustomPluralization : IPluralizationService
{
public string Pluralize(string word)
{
return word.Pluralize();
}
public string Singularize(string word)
{
return word.Singularize();
}
}
In my context;
modelBuilder.Configurations.Add<Config>(.. ?? ..)
According to msdn's article Code-Based Configuration (EF6 onwards) section Using DbConfiguration, it is sufficient to simply place your DbConfiguration class in the same assembly as your DbContext class.
Nevertheless you can specify it manually, as explained in the article by using either the config file or an annotation in your DbContext.
Config file:
<entityFramework codeConfigurationType="MyNamespace.MyDbConfiguration, MyAssembly">
<!-- Your EF config -->
</entityFramework>
Annotation:
[DbConfigurationType("MyNamespace.MyDbConfiguration, MyAssembly")]
public class MyContextContext : DbContext
{
}
Or
[DbConfigurationType(typeof(MyDbConfiguration))]
public class MyContextContext : DbContext
{
}
Note:
These examples are directly from the article I linked