How to add-migrations for auto-generated databases? - sql-server

I have an application which contains to context classes. One is master context class and second is sub context class. When I run the application for the first time the master database gets generated. And whenever I create a new user, a database related to that user gets generated using sub context class. For example, if I create 10 users then 10 databases will get generated using sub context class like sub_db_userId.
The problem is enabling migrations in this complex structure. I know some people would say it's not appropriate to create new database use foreign key relation but I have to work on requirements.
I found this thread very helpful in finding how to enable-migrations for separate context classes but in my scenario, it does not apply changes to existing databases because of database name is associated with user ids. Rather applying changes to existing child databases it creates new database without user id like this sub_db_. How can I solve this issue?
The way I am creating the new database for every user is given below.
My context classes:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection", throwIfV1Schema: false) {}
}
public class SubDbContext : DbContext
{
public DbSet<Country> Countries { get; set; }
public DbSet<City> Cities { get; set; }
public SubDbContext() : base("SubDatabaseConnection")
{
}
public SubDbContext(string connectionString) : base(connectionString)
{
Database.SetInitializer<SubDbContext>(new
CreateDatabaseIfNotExists<SubDbContext>());
}
}
Connection strings:
<add name="DefaultConnection"
connectionString="Data Source=.\SQLExpress;Initial Catalog=master_db;Integrated Security=True"
providerName="System.Data.SqlClient" />
<add name="SubDatabaseConnection"
connectionString="Data Source=.\SQLExpress;Initial Catalog={0};Integrated Security=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
I am using {0} for formatting purposes. How can I enable migrations and apply changes to existing databases?
Modifications: I am linking tables to database in Register action like this:
SubDbContext newContext = new SubDbContext(string.Format(userDatabase, "sub_db_" + userId));
newContext.Countries.FirstOrDefault();
newContext.Cities.FirstOrDefault();

Your DbContext for all your sub-databases is SubDbContext. So you must enable migration based on one of them. then put this code as Configuration class:
internal sealed class Configuration : DbMigrationsConfiguration<SubDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
}
and put this code into the SubDbContext constructor:
Database.SetInitializer<SubDbContext>(new MigrateDatabaseToLatestVersion<SubDbContext, Configuration>());
it means, every database when found a new manual added Migration,
then try to migrate it.
and also you can use this approache too:
write this code in the Application_Start:
var context = new SubDbContext("your generated connection string");
var initializeMigrations = new MigrateDatabaseToLatestVersion<SubDbContext, Configuration>();
initializeMigrations.InitializeDatabase(context);
I hope you find it helpful.

Related

How do I access the elmah database from code?

VS2013 update 4, MVC5, elmah.mvc (same as elmah), VB/C#
The following code is part of the standard MVC template to get started and it is part of setting up our database connection from within code to access an SQL database:
Public Class ApplicationDbContext
Inherits IdentityDbContext(Of ApplicationUser)
Public Sub New()
MyBase.New("DefaultConnection", throwIfV1Schema:=False)
Me.Configuration.LazyLoadingEnabled = True
End Sub
Public Shared Function Create() As ApplicationDbContext
Return New ApplicationDbContext()
End Function
We also need the following or something similar in web.config:
<configuration>
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=mypc\SQLEXPRESS;Initial Catalog=mydb.DefaultContext;Integrated Security=True" providerName="System.Data.SqlClient" />
<add name="ElmahConnection" connectionString="Data Source=mypc\SQLEXPRESS;Initial Catalog=mydb.elmah;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
I added the elmah connection string as it is relevant to my question.
Then in each location where needed, the following definition is added and we can access the database tables using db.< tablename>...:
Private db As New ApplicationDbContext
I want to write some methods to work with and on the elmah data table but it is a different context than ApplicationContext. I don't quite understand what I would write to setup a connection to the elmah table since I didn't really set that up, it came in the dll for elmah.
While keeping error records makes sense, during development I wanted to clear the Elmah log. While probably trivial for most, it was a good exercise to figure it out. I was so used to code first, I forgot EF also does database first.
In VS2013 update 4 the following Wizard made this task pretty easy.
1) Project > Add New Item > Data > ADO.NET Entity Data Model
2) Give the model a name (With great creativity I used 'elmah') > Click Add
3) This is where it gets pretty cool. I'm not sure when it was added but the EF framework now includes a new choice called Code First From Database. Click on that.
4) Select the elmah connection string
Note: There is an option to save connection settings in web.config. That simply creates a duplicate connection string. Leave it checked or don't, but using the existing string is fine. I didn't select the option and web.config was left untouched. However, not using that option means the connection string name will have to be updated in the context definition > Click Next
5) Click on Tables to load the Elmah table, leave the defaults as is > Click Finish
The wizard creates 2 files and places them in the project. One is named by the data table name which is ELMAH_Error; this is the model. The other is a parital class that sets up the context. If the save connection option was selected then web.config will be modified to add the new connection string.
Note: I combined the 2 Classes into a single file for convenience (may require adding some Using or Imports) and the Public Sub New() is where the connection string name must be updated if the existing connection string is used as shown below.
Partial Public Class elmah
Inherits DbContext
Public Sub New()
MyBase.New("name=ElmahConnection")
End Sub
Public Overridable Property ELMAH_Error As DbSet(Of ELMAH_Error)
Protected Overrides Sub OnModelCreating(ByVal modelBuilder As DbModelBuilder)
End Sub
End Class
6) With all that automatically done (except for the connection string name if required), all that is required is to write the desired code. I wanted to empty the elmah log from time to time and used the following:
Public Class ErrorController
Inherits Controller
Private db1 As New elmah
Function DeleteElmahRecords() As ActionResult
Dim elmahTable = db1.ELMAH_Error.ToList()
db1.ELMAH_Error.RemoveRange(elmahTable)
db1.SaveChanges()
Return RedirectToAction("ErrorTesting")
End Function
…
End Class
Obviously I have a method called ErrorTesting that the function returns to and I access this method from a link on that same page.
Hope this is useful for someone. It's kind of the only way I can give back considering the awesome guru help I often get from this site.

How come my ContextInitializer for EF 6 has zero refrences?

I'm trying to learn EF 6 Code-first in WPF by following some tutorials. Since I'm familiar with model-first I can understand most parts except I've found ContextInitializer a little confusing. I defined a ContextInitializer like this code:
public class ContextInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
var customers = new List<Customer>
{
new Customer{Name="Jane",Phone="2238718"},
new Customer{Name="David",Phone="43245608"},
new Customer{Name="Mike",Phone="90814417"}
};
customers.ForEach(cu => context.Customers.Add(cu));
context.SaveChanges();
}
}
and this is my Context class:
public class Context : DbContext
{
public Context()
: base("MVVM")
{
}
public DbSet<Customer> Customers { get; set; }
}
and It created a database at first run which I think it's weird because this class has zero refrences. Since Seed method doesn't fire again, I can't understand how this works.
Can someone explain to me how my ContextInitializer with zero reference created a database?
Does the following section exist in your App.Config?
<contexts>
<context type="(your name space).Context, MVVM">
<databaseInitializer type="(your name space).ContextInitializer, MVVM" />
</context>
</contexts>
If it is, the program knows where to look to find the ContextInitializer. If the database already exists and the tables in the database already match those of the POCO/model classes, nothing happens. If the model has changed or the database doesn’t exist, this class will be invoked, resulting in the database being seeded with your data.

Entity Framework: multiple DB having the same schema

I have just created an ASP.NET MVC 4 & WebAPI project. After that I have added .edmx data source to project.
I have multiple databases with the same schema. Dynamically I want to replace connection string using default constructor provided in EF.
But in Model1.Designer.cs, every time I get error like "Member with same signature already declared".
I'm unable to solve this problem.
Yes, it works! All you need to change is the connection string.
And I have just tested it in order to satisfy my own curiosity.
Here are the steps that I took:
Take an existing database and create a model for it.
Create a new empty database.
In SQL Management Studio right click the first database -> Tasks -> Export Data. Export all it's data to the newly created database.
Remove some records from the second database.
Write this code:
TMS_MiscEntities db = new TMS_MiscEntities();
TMS_MiscEntities dbCopy = new TMS_MiscEntities();
dbCopy.Database.Connection.ConnectionString = db.Database.Connection.ConnectionString.Replace("initial catalog=TMS_Misc", "initial catalog=TMS_Misc_new");
Response.Write(string.Format("DB 1 records: {0}<br/>", db.ZipCodes.Count()));
Response.Write(string.Format("DB 2 records: {0}<br/>", dbCopy.ZipCodes.Count()));
Check results:
DB 1 records: 869164
DB 2 records: 868709
Conclude that it works :)
This is how my connection string looks:
<add name="TMS_MiscEntities" connectionString="metadata=res://*/DbModel.csdl|res://*/DbModel.ssdl|res://*/DbModel.msl;provider=System.Data.SqlClient;provider connection string="data source=ws2008;initial catalog=TMS_Misc;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I'm using Entity Framework 6.1.3. I have added a constructor to my DbContext that takes a string parameter. This string can be the name of the connection stored in your App.config or a full connection string. Something like this:
public partial class MyDBContext : DbContext
{
public MyDBContext(string connectionString)
: base(connectionString)
{
}
// DbSets, OnModelCreating, etc
}
In my case, I manage a multi-tenant application and I use a ContextFactory to build the proper connection string and return my initialized context.
public class ContextFactory
{
public MyDbContext GetContext()
{
string connectionString;
// do some stuff here
return new MyDbContext(connectionString);
}
}

Database error InValidOperationException when attempting to save to database

I get this error when I attempt to save to the database.
In the Controller I have the Edit HttpPut
public ActionResult EditSubject(Models.xxxx model)
{
//Database Model Class
SubjectDB subjectdb = new SubjectDB();
// Name of DB Access in Web.config
BeaconDBEntities db = new BeaconDBEntities();
if (ModelState.IsValid)
{
subjectdb.SubjectId = model.SubjectId;
db.SubjectDBs.Add(subjectdb); --> Pops InvalidOperationsException
db.SaveChanges();
}
In Models folder is the model for the database table
SubjectDB.cs
namespace xxx.Models
{
public class SubjectDB
{
public string SubjectId { get; set;}
}
public class BeaconDBEntities: DbContext
{
public DbSet<SubjectDB> SubjectDBs { get; set; }
}
}
Web.config is the connect string for the database
<coneectionStrings>
<add name="BeaconDBEntities" ...............
</connectionStrings>
The first thing I see is that your connection string name 'BeaconDBEntites' does not match your DbContext inherited class name 'BeaconDBEntities' (you are missing an 'i' in the word Entities). Try changing that and see if it fixes it.
When you edit your data then i think you don't need to write code like this when your useing entity framework it's below code
db.SubjecDBs.Add(subjectdb);
db.SaveChanges();
first when you update your data then first your get your data with your id like this it's below
and your create object your entity class. your entity class is your table like below
SubjecDBs objsub=new SubjecDBs();
var data =db.db.SubjecDBs.where(x=>x.SubjectID==ID).ToList();
then you match your data which is you wont to update like below
objsub.SubjecName=data[0].SubjecName
and you match your field which you wont to update then your write below code like this
db.SaveChanges();
i think this will help you...

Mapping entities to ASPNETDB.MDF MVC3

In order to avoid having two databases, I have mapped my entities to ASPNETDB.MDF, which is made automatically for membership. I was following this article in order to map my entities to existing database: http://weblogs.asp.net/scottgu/archive/2010/08/03/using-ef-code-first-with-an-existing-database.aspx
From what I understand all I need to do change is the name of the databse for the context class like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using UniversityApp.Models;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace UniversityApp.DAL
{
public class ASPNETDB : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Review> Reviews { get; set; }
public DbSet<Movie> Movies { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
Also I have changed the connection string like this:
<connectionStrings>
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
<add name="MovieContext" connectionString="Data Source=|DataDirectory|aspnetdb.mdf" providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
Everything seems to work fine (methods to the old database, reading and writing to the databse, even the initialization data). But still when I open the connection to ASPNETDB.mdf I don't see my tables there. What am I doing wrong?
I think you're going to run into more issues here such that in general this may not be the best approach right now. That being said, to answer your actual question, DbContext is looking for a connection string with the same name as your context. That is, it's looking for a connection string named "ASPNETDB". Since your connection strings are named "ApplicationServices" and "MovieContext" DbContext is not finding either of these.
To make DbContext use a specific connection string just pass that connection string to the DbContext constructor. For example:
public class ASPNETDB : DbContext
{
public ASPNETDB()
: base("name=ApplicationServices")
{
}
...
}
Once you get this working you'll probably want to look into using Migrations to create tables in a database that already exists.

Resources