Dynamic MySQL database connection for Entity Framework 6 - c#

I wish to pass a dynamic connection string to the entity framework context. I have over 150 schemas which are identical (one per account) and I would like to select the connection as such:
ApplicationDbContext db = new ApplicationDbContext("dbName");
In theory this would be fairly easy, as I can create a connectionString and pass it as the argument for the constructor, for example:
public ApplicationDbContext(string dbName) : base(GetConnectionString(dbName))
{
}
public static string GetConnectionString(string dbName)
{
// The connectionString passed is something like:
// Server=localhost;Database={0};Uid=username;Pwd=password
var connString = ConfigurationManager
.ConnectionStrings["MyDatabase"]
.ConnectionString
.ToString();
return String.Format(connString, dbName);
}
I can connect successfully when I just pass the connection string name, but not when I generate it dynamically as below. I realize now that it's because the connection string in web.config has the providerName="MySql.Data.MySqlClient" attribute in it.
When I pass the actual connection string dynamically to the connection though, it assumes that it needs to connect to SQL Server rather than MySQL and fails due to the connection string being invalid.
The question is, how do I pass the provider name to the connection string if I am creating it dynamically?

Entity Framework 6 offers some handy subtle changes which aid in both getting MySQL working and also creating dynamic database connections.
Getting MySQL working with Entity Framework 6
First, at the date of my answering this question, the only .Net connector drivers compatible with EF6 is the MySQL .Net Connectior 6.8.1 (Beta development version) which can be found at the official MySQL website here.
After installing, reference the following files from your Visual Studio solution:
Mysql.Data.dll
Mysql.Data.Entity.EF6.dll
You will also need to copy these files somewhere where they will be accessible to the project during build time, such as the bin directory.
Next, you need to add some items to your Web.config (or App.config if on desktop based) file.
A connection string:
<connectionStrings>
<add name="mysqlCon"
connectionString="Server=localhost;Database=dbName;Uid=username;Pwd=password"
providerName="MySql.Data.MySqlClient" />
</connectionStrings>
Also add the provider, inside the <entityFramework /> and <providers /> nodes, optionally (this is an absolute must in the second part of my answer, when dealing with dynamically defined databases) you may change the <defaultConnectionFactory /> node:
<entityFramework>
<defaultConnectionFactory type="MySql.Data.Entity.MySqlConnectionFactory, MySql.Data.Entity.EF6" />
<providers>
<provider invariantName="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlProviderServices, MySql.Data.Entity.EF6" />
</providers>
</entityFramework>
If you change the defaultConnectionFactory from the default sql server connection, don't forget to remove the <parameter> nodes which are nested in the defaultConnectionFactory node. The MysqlConnectionFactory does not take any parameters for its constructor and will fail if the parameters are still there.
At this stage, it's quite easy to connect to MySQL with Entity, you can just refer to the connectionString above by name. Note that if connecting by name, this will work even if the defaultConnectionFactory node still points at SQL Server (which it does by default).
public class ApplicationDbContext: DbContext
{
public ApplicationDbContext() : base("mysqlCon")
{
}
}
The it is just a matter of connecting normally:
ApplicationDbContext db = ApplicationDbContext();
Connecting to a dynamically selected database name
At this point it's easy to connect to a database which we can pass as a parameter, but there's a few things we need to do.
Important Note
If you have not already, you MUST change the defaultConnectionFactory in Web.config if you wish to connect to MySQL
dynamically. Since we will be passing a connection string directly to
the context constructor, it will not know which provider to use and
will turn to its default connection factory unless specified in
web.config. See above on how to do that.
You could pass a connection string manually to the context like this:
public ApplicationDbContext() : base("Server:localhost;...")
{
}
But to make it a little bit easier, we can make a small change to the connection string we made above when setting up mySQL. Just add a placeholder as shown below:
<add name="mysqlCon" connectionString="Server=localhost;Database={0};Uid=username;Pwd=password" providerName="MySql.Data.MySqlClient" />
Now we can build a helper method and change the ApplicationDbContext class as shown below:
public class ApplicationDbContext: DbContext
{
public ApplicationDbContext(string dbName) : base(GetConnectionString(dbName))
{
}
public static string GetConnectionString(string dbName)
{
// Server=localhost;Database={0};Uid=username;Pwd=password
var connString =
ConfigurationManager.ConnectionStrings["mysqlCon"].ConnectionString.ToString();
return String.Format(connString, dbName);
}
}
If you are using database migrations, the following step is important
If you are using migrations, you will find that the ApplicationDbContext will be passed to your Seed method by the framework and it will fail because it will not be passing in the parameter we put in for the database name.
Add the following class to the bottom of your context class (or anywhere really) to solve that problem.
public class MigrationsContextFactory : IDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext Create()
{
return new ApplicationDbContext("developmentdb");
}
}
Your code-first migrations and seed methods will now target the developmentdb schema in your MySQL database.
Hope this helps someone :)

It's now 2019 of course things have changed a bit but Franciso's example really helped me on this. This is the simplest solution I could find and the only one that actually worked. I did change it a bit from what he has shown. Follow this to completion you should end up with a working solution.
I had to change a few things. I am going to be very explicit in what has to be done and I am going to use my actual file names etc so that you don't have to guess about substitutions. Many examples are also short on how to make it work at the end. This example has everything you need to know.
This was built on visual studio 2015 Entityframework 6 using MySql server 8.0.16.0.
Unfortunately the MySql connectors and libraries are a complete mess. The 8.0.xx.0 connector / net and MySql.Data.Entity.EF6 and MySql.Data are completely useless.
I have installed Connector Net 6.10.7.0, MySql.Data.Entity.EF6 6.10.7.0, and MySql.Data 6.10.7.0. That works for me and I will vigorously oppose changing this.
This is for MySql but I really don't know why it could not work for any db.
Scenario
I have a multi tenant situation where I have a common db and multiple tentant databases, one per customer The customer id is kept in the common db for login purposes and authorizaton and the customer id directs which database to use. The client db's are all called myclientdb_x where x is the client number. myclientdb_1, myclientdb_2, myclientdb_35 and so on.
I need to dynamically switch to whatever clientdb_x the code is currently serving. There is a initial database client called myclient_0 which is the template for all of the other myclient_x databases.
Step1
I created a specific connection string in my Web.config for this it looks like this. It allows connections to the clientdb_0
<add name="DefaultClientConnection" providerName="MySql.Data.MySqlClient"
connectionString="server=localhost;user id=xxx;
password=xxxx; persistsecurityinfo=True;database=clientdb_0" />
Step2
I created a new entity called ClientDbUserUpdater using the wizard. The data entity is called
ClientDbUserUpdater.edmx
I told it to use "DefaultClientConnection" as the DB connection
I told it to save this new connection string in the Web.config
This created new entity connection string in the Web.config file and it will look like
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database=myclient_0"" providerName="System.Data.EntityClient" />
You might have to dig a bit because the wizard is not good about putting in \n in appropriate places.
Notice that this connection string is fundamentally the same as the initial connection string except for its name and the fact that it has
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
The res: strings are needed by the data entity and its why you can't just send a standard connection string into the data entity.
If you try to send in the initial connection string
<add name="DefaultClientConnection" providerName="MySql.Data.MySqlClient"
connectionString="server=localhost;user id=xxx;
password=xxxx; persistsecurityinfo=True;database=clientdb_0" />
you will get an exception from
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
Step3
This new connection string is the one you need to alter. I have not tested it but I am pretty sure if change the data entity model with the wizard you will need to make this change again.
Take string:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database=myclient_0"" providerName="System.Data.EntityClient" />
and change it to:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database={0}"" providerName="System.Data.EntityClient" />
Notice that the only part changed is database=myclient_0 to database={0}
Step 4
The data entity created some code behind ClientDbUserUpdater.edmx. The file is called ClientDbUserUpdater.Context.cs.
The code is ...
namespace what.ever.your.namespace.is
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class client_0Entities : DbContext
{
public client_0Entities()
: base("name=client_0Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<user> users { get; set; }
}
}
Notice that this a partial class. This means you can extend this class and add a new constructor.
Add the following class.
using System;
using System.Configuration ;
using System.Data.Entity ;
namespace what.ever.your.namespace.is
{
public partial class client_0Entities : DbContext
{
public client_0Entities(string dbName) : base(GetConnectionString(dbName))
{
}
public static string GetConnectionString(string dbName)
{
var connString = ConfigurationManager.ConnectionStrings["client_0Entities"].ConnectionString.ToString();
// obviously the next 2 lines could be done as one but creating and
// filling a string is better for debugging. You can see what happened
// by looking a conn
// return String.Format(connString, dbName);
string conn = String.Format(connString, dbName);
return conn ;
}
}
}
The class adds a new constructor which allows you to get the base connection string for the data entity model which from above looks like:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database={0}"" providerName="System.Data.EntityClient" />
and modfiy it at run time to change the schema.
The String.Format() call in the new partial class swaps out the database schema name in this connection string at run time.
At this point all configuration is done.
Step 5
Now you can make it go. For better understanding of this example it is nice to know what the model looks like for this entity. It is very simple because I was just testing and trying to make it go.
Drilling down through ClientDbUserUpdater.edmx and into into ClientDbUserUpdater.tt you will find your model in modelname.cs . My model is called "user" so my file name is called user.cs
namespace what.ever.your.namespace.is
{
using System;
using System.Collections.Generic;
public partial class user
{
public int UserId { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<bool> Active { get; set; }
}
}
Now you can generally access your model like this.
client_0Entities _client_0Entities = new client_0Entities("schemaName");
and this code can be anywhere in your solution that can see class client_0Entities.
which in practice is a line similar to any of the 3 below which are connection to databases client_19, client_47 and client_68 respectively.
client_0Entities _client_0Entities = new client_0Entities("client_19");
client_0Entities _client_0Entities = new client_0Entities("client_47");
client_0Entities _client_0Entities = new client_0Entities("client_68");
the following is an actual code example that works on my system. Obviously I am going to not hard code in "client_19" but its better for demo purposes.
here is actual code with real names that works and adds a new row to the user table on database client_19
string _newSchema = "client_19"
using(client_0Entities _client_0Entities = new client_0Entities(_newSchema))
{
user _user = new user();
_user.UserId = 201;
_user.Email = "someone#someplace.com"
_user.FirstName ' "Someone";
_user.LastName = "New";
_user.Active = true;
client_0Entities.users.Add ( _user ) ;
client_0Entities.SaveChangesAsync ( ) ;
}
Hopefully this helps some people. I spent about 20 hrs looking at different solutions which simply did not work or provide enough information to complete them. As I said, finding Franciso's example allowed me to get it working.
Regards,

Related

Entity Framework - Invalid Object with custom connections string

Just for a brief overview this is how I added the database into my project:
I have added a datasource by adding an ADO.NET Data Model Entity and selecting EF Designer from Database.
Doing so has generated a connection string for me in my web.config. Integrated Security is set to true (if that matters).
Once connected I right clicked and selected 'Update model from database.
Since there is multiple environments I built a custom context with a parametized constructor. Code looks as such (condensed and censored):
public partial class DataEntities : DbContext
{
public DataEntities(string connectionString)
: base(connectionString)
{
}
}
With each environment there are different local sql accounts associated. Requiring me to generate a connection string that is associated with the correct account in the correct environment. Doing so my web config looks something like this:
<connectionStrings>
<add name="DataEntities" connectionString="metadata=res://*/Models.XXModel.XXModel.csdl|res://*/Models.XXModel.XXModel.ssdl|res://*/Models.XXModel.XXModel.msl;provider=System.Data.SqlClient;provider connection string="data source=MYSQLSERVER;initial catalog=Data;integrated security=True;MultipleActiveResultSets=True;application name=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
<secureConnectionStringsSection passwordPolicy="AllowLocalPasswordsForConnectionStrings">
<secureConnectionStrings>
<add name="DataEntities-Local" providerName="System.Data.SqlClient" connectionString="data source=MYSQLSERVER;user id=ACCNT; password=PASSWORD;" />
</secureConnectionStrings>
</secureConnectionStringsSection>
When I am instantiating my DataEntity object, I am calling a helper function I have written to get my custom connection string. I am doing so via the following code:
private DataEntities adDB = new DataEntities(XXX.Helpers.EFDBHelper.getDataConnectionString());
I can verify that my connection string helper does correctly pull the custom connection string that I have in my web.config. However once I actually try to make a call on the database I am left with the following error:
Invalid object name 'dbo.mycolumn'.
I know that my parametized constructor is being called with the correct connection string. I also know my connection string is valid, I have tested it in powershell:
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "data source=MYSQLSERVER;user id=ACCNT;password=PASSWORD"
$conn.Open()
$conn.Close()
I am certain that it is not an issue with the database itself as well. The moment I remove the parameter from my Entity initialization:
private DataEntities adDB = new DataEntities();
I am able to pull data from the database. I am assuming that it uses the auto-generated connection string. Which won't work since I cannot use integrated security once it goes past my local environment.
My apologies, I am new to the technology here. I am sure that it is just something small that I am missing.
In my connection string I did not specify a catalog.
Since I am newish to the technology, I tried to simply replicate some of the existing code that I had inherited. In the connection string I tried to replicate from, no catalog was expressed as well.
However... the account I am using to talk to the new datasource has access to all levels of the database so the catalog was required. The old inherited database had only one catalog the the sql account had access too.
You live and you learn!

Remove ConnectionString from Web.config using Entity Framework CodeFirst

Transform web.config won't work well for Entity Framework CodeFirst because the connection string is added dynamically after transform when publishing. We have a dynamic connection settings being set in code for CodeFirst when releasing to different environments.
I have tried the correct removal method but the published results ends up with the connection string in the web.config.
Are there any work arounds for this? Putting connection info in our web.configs isn't an option. Adding the connection info dynamically at runtime works well.
The problem is when publish adds the connection info in the web.config the app gets a 500 error because codefirst is attempting to use an invalid connection string for the environment that is not sandbox where it was created.
We are changing that at runtime here and that is working.
public MyAppDataContext()
{
this.Database.Connection.ConnectionString = OurDynamicConfigSettings.GetSetting("MyAppConnectionString");
}
The codefirst though is attempting to use what is in web.config before we set it dynamically. The fix is to remove the connection info from the web.config.
It all works except when building on build server or publishing, codefirst inserts the connection info back into the web.config every time we publish. Having to remember to remove this each time is not good practice and prone to errors if you forget.
Code for removing connection string in our transform file should work but doesn’t.
<connectionStrings>
<add xdt:Transform="Remove" xdt:Locator="XPath(configuration/connectionStrings[#name='MyAppConnectionString'])" />
</connectionStrings>
Your transform should be:
<connectionStrings>
<add xdt:Transform="Remove" xdt:Locator="Match(name)" name="MyAppConnectionString" />
</connectionStrings>
But, I have to ask.. are connection strings stored in your database or something? Why do you need to do them in code?
You could just do this:
public class MyDataContext : DbContext {
public MyDataContext(string connectionString) : base(connectionString)
...
}
Then when you create you contexts, you do this:
using(var context =
new MyDataContext(OurDynamicConfigSettings.GetSetting("MyAppConnectionString"))) {
...
}
public partial class MyContextEntities : DbContext
{
public MyContextEntities(string ConnectionString="[Your Entity Connection String Here]")
: base(ConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
Replace " with ' (single quote) in connection string

The entity type <type> is not part of the model for the current context

I am getting into the Entity Framework, but I am unsure if I am missing a critical point in the code-first approach.
I am using a generic repository pattern based on the code from https://genericunitofworkandrepositories.codeplex.com/ and have created my entities.
But when I try to access or modify the entity I run into the following:
System.InvalidOperationException: The entity type Estate is not part
of the model for the current context.
It happens when I am trying to access it from my repository:
public virtual void Insert(TEntity entity)
{
((IObjectState)entity).ObjectState = ObjectState.Added;
_dbSet.Attach(entity); // <-- The error occurs here
_context.SyncObjectState(entity);
}
The database (./SQLEXPRESS) is created just fine, but the entities (tables) is just not created on startup.
I am wondering if I need to explicit set the mapping of the entities? Is EF not able to this by its own?
My Entity is:
public class Estate : EntityBase
{
public int EstateId { get; set; }
public string Name { get; set; }
}
My context is as so:
public partial class DimensionWebDbContext : DbContextBase // DbContextBase inherits DbContext
{
public DimensionWebDbContext() :
base("DimensionWebContext")
{
Database.SetInitializer<DimensionWebDbContext>(new CreateDatabaseIfNotExists<DimensionWebDbContext>());
Configuration.ProxyCreationEnabled = false;
}
public new IDbSet<T> Set<T>() where T : class
{
return base.Set<T>();
}
}
Is there any specific reason why this error occurs? I have tried enable migrations and enable automatic migrations without any help either.
Put this in your custom DbContext class:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Estate>().ToTable("Estate");
}
If your tables are not created on startup, this is why. You need to tell the DbContext about them in the OnModelCreating method override.
You can either do custom per-entity mappings here, or separate them out into separate EntityTypeConfiguration<T> classes.
Apparently, this error is very generic, it could have a number of reasons. In my case, it was the following: The connection string (in Web.config) generated by the .edmx was invalid. After almost a day of trying everything, I changed the connection string from the EF string to an ADO.NET string. This solved my issue.
For example, the EF string looks something like this:
<connectionStrings>
<add name="BlogContext"
connectionString="metadata=res://*/BloggingModel.csdl|
res://*/BloggingModel.ssdl|
res://*/BloggingModel.msl;
provider=System.Data.SqlClient
provider connection string=
"data source=(localdb)\v11.0;
initial catalog=Blogging;
integrated security=True;
multipleactiveresultsets=True;""
providerName="System.Data.EntityClient" />
</connectionStrings>
And the ADO.NET string looks like this:
<connectionStrings>
<add name="BlogContext"
providerName="System.Data.SqlClient"
connectionString="Server=.\SQLEXPRESS;Database=Blogging;
Integrated Security=True;"/>
</connectionStrings>
Source: http://msdn.microsoft.com/nl-nl/data/jj556606.aspx
For me the issue was that I had not included the Entity Class within my db set inside the context for entity framework.
public DbSet<ModelName> ModelName { get; set; }
You may try removing the table from the model and adding it again. You can do this visually by opening the .edmx file from the Solution Explorer.
Steps:
Double click the .edmx file from the Solution Explorer
Right click on the table head you want to remove and select "Delete from Model"
Now again right click on the work area and select "Update Model from Database.."
Add the table again from the table list
Clean and build the solution
The problem may be in the connection string. Ensure your connection string is for SqlClient provider, with no metadata stuff related to EntityFramework.
My issue was resolved by updating the metadata part of the connection string. Apparently it was pointing at the wrong .csdl / .ssdl / .msl reference.
I've seen this error when an existing table in the database doesn't appropriately map to a code first model. Specifically I had a char(1) in the database table and a char in C#. Changing the model to a string resolved the problem.
One other thing to check with your connection string - the model name. I was using two entity models, DB first. In the config I copied the entity connection for one, renamed it, and changed the connection string part. What I didn't change was the model name, so while the entity model generated correctly, when the context was initiated EF was looking in the wrong model for the entities.
Looks obvious written down, but there are four hours I won't get back.
For me the issue was that I used the connection string generated by ADO.Net Model (.edmx). Changing the connection string solved my issue.
This can also occur if you are using a persisted model cache which is out of date for one reason or another. If your context has been cached to an EDMX file on a file system (via DbConfiguration.SetModelStore) then OnModelCreating will never be called as the cached version will be used. As a result if an entity is missing from your cached store then you will get the above error even though the connection string is correct, the table exists in the database and the entity is set up correctly in your DbContext.
The message was pretty clear but I didn't get it at first...
I'm working with two Entity Framework DB contexts sysContext and shardContext in the same method.
The entity I had modified\updated is from one context but then I tried to save it to the other context like this:
invite.uid = user.uid;
sysContext.Entry(invite).State = EntityState.Modified;
sysContext.SaveChanges(); // Got the exception here
but the correct version should be this:
invite.uid = user.uid;
shardContext.Entry(invite).State = EntityState.Modified;
shardContext.SaveChanges();
After passing the entity to the correct context this error went away.
I was facing the same issue with EntityFrameworkCore trying to update a range of values.
This approach did not work
_dbSet.AttachRange(entity);
_context.Entry(entity).State = EntityState.Modified;
await _context.SaveChangesAsync().ConfigureAwait(false);
After adding UpdateRange method and removing attach and entry everything work
_dbSet.UpdateRange(entity);
await _context.SaveChangesAsync().ConfigureAwait(false);
Sounds obvious, but make sure that you are not explicitly ignoring the type:
modelBuilder.Ignore<MyType>();
map of the entity (even an empty one) added to the configuration will lead to having the entity type be part of the context. We had an entity with no relationship to other entities that was fixed with an empty map.
if you are trying DB first then be sure that your table has primary key
Visual Studio 2019 seems to cause this for me. I fixed it by generating the edmx model again in 2017.
For me it was caused because I renamed the entity class.When I rolled it back it was Ok.
I had this
using (var context = new ATImporterContext(DBConnection))
{
if (GetID(entity).Equals(0))
{
context.Set<T>().Add(entity);
}
else
{
int val = GetID(entity);
var entry = GetEntryAsync(context, GetID(entity)).ConfigureAwait(false);
context.Entry(entry).CurrentValues.SetValues(entity);
}
await context.SaveChangesAsync().ConfigureAwait(false);
}
This was in an async method, but I've forgot to put await before GetEntryAsync, and so I got this same error...
Make sure you have set up your mapping class to point to your SQL table
I've had the same problem and in my case, the reason why I got this error message was that the property identifiers in my class file did not match the identifiers defined in the database, e.g. I wrote an identifier with a beginning uppercase letter while in the database it was all lowercase.
I've faced this issue after publishing my project using web deploy. It happened because my the metadata in connection string of my publish profile was not same as connection string in my project because I dropped the edmx for some reason and added it back with different Name. To fix it I had to delete the publish profile and redeploy again so that the metadata matches the names.
With models created from database (First Database), it is not possible to replace the connection string (with metadata and providerName="System.Data.EntityClient", from EDMX) by one of SQL.
The only possibility I have found is to create another context that uses the SQL connection (providerName="System.Data.SqlClient")
<connectionStrings>
<add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Max Pool Size=10000;Pooling=true;Data Source=MyIpServer;Initial Catalog=myDatabase;Persist Security Info=True;User ID=MyUser;Password=MyPassword;TrustServerCertificate=False" />
<add name="Entities" providerName="System.Data.EntityClient" connectionString="metadata=res://*/Datos.MyModel.csdl|res://*/Datos.MyModel.ssdl|res://*/Datos.MyModel.msl;provider=System.Data.SqlClient;provider connection string="Max Pool Size=10000;Pooling=true;data source=MyIpServer;initial catalog=myDatabase;persist security info=True;user id=MyUser;password=MyPassword;trustservercertificate=False;MultipleActiveResultSets=True;App=EntityFramework"" />
</connectionStrings>
With the two context options, with Identity:
public partial class ContextWithUsers : IdentityDbContext<MyUser>
{
public ContextWithUsers() : base("name=DefaultConnection")
{
}
}
public class MyUser : IdentityUser
{
// aditional table user data
//public virtual MyUserInfo MyUserInfo { get; set; }
}
Normal context:
public partial class ContextWithoutUsers : DbContext
{
public ContextWithoutUsers () : base("name=Entities")
{
}
}
This solution works, but... Why is it not possible to use the same context with the First Database model + Identity ?
NOTE 1: if you force change connection string show:
System.Data.Entity.Infrastructure.UnintentionalCodeFirstException: 'The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715'
NOTE 2: External Class library with EDMX + Data and ASP.NET webform project
Delete the .edmx file and add it again. Especially, if you have upgraded the Entity Framework.
Could be stupid, but if you only got this error on some Table, dont forget to clean your project and rebuild (could save a lot of time)

Entity Framework Code First with non-user instance

these are my first steps with Entity Framework Code First workflow, so maybe I am missing something simple. I created my context class inheriting from DbContext
public class Context : DbContext
{
public DbSet<Book> Books { get; set; }
public DbSet<Author> Authors { get; set; }
}
And I executing it in a controller code:
var author = new Author()
{
FirstName = "Julia",
LastName = "Lerman"
};
using (var context = new Context())
{
context.Authors.Add(author);
context.SaveChanges();
}
I have no other code or configuration that i set for EF.
When I start the application and hit code in controller everything works fine, the only problem is that database is actually not created in SQL Server but it runs, somewhat, locally. That means I cannot really use SQL Server management studio to inspect the data when my application runs, which I want to do.
I figured out that in web.config automatically folowing key was added:
<add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=false;" providerName="System.Data.SqlClient" />
How can I modify this config key (or is there anything else that I need to do) to make sure that this database will run on actual SQL Server express rather than in-process?
OK, I figured it out, thanks to "Programming Entity Framework: Code First" book, apparently it is the convention over configuration scenario, for the query string to be picked up the name of it needs to match the name of the Context class (the one you inherit from DbContext).
Therefore I need to add new connection string like below:
<add name="Context" connectionString="Data Source=.\SS2012EXPRESS;Initial Catalog=HomeLibrary;Integrated Security=True" providerName="System.Data.SqlClient" />
Original connection string can stay as it is, it is not used run-time. I am not entirely sure what is the purpose of it.

DbContext behave differently within different classes

I have a local ASP.NET MVC 3 Windows Azure Project where I use a local instance of MSSQL Express for my emulator.
In my web.config I have the following connection string:
<add name="ExampleDb" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Initial Catalog=ExampleDb;User Instance=true;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />
For debugging purposes I have the following in my WebRole.cs file:
public override bool OnStart()
{
ExampleDb context = new ExampleDb();
context.ExampleItemEntries.Add(new ExampleItem() { ExampleItemId = 1, Att1 = "1", Att2 = "2" });
context.SaveChanges();
return base.OnStart();
}
When I perform this action I can actually see the content in my code-first generated database (using Entity Framework). Database: ExampleDb, Table: ExampleItem.
However, doing the exact same thing in ExampleController does NOT update the database. Instead this data goes somewhere else (I have no idea where). When I visit my controller via the browser I can upload data and look at it but it is not stored in my ExampleDb database, only data sent from WebRole.cs is in the database.
Any ideas what's causing this behaviour?
ExampleDb.cs looks like this:
public class ExampleDb : DbContext
{
public ExampleDb() : base("ExampleDb") { }
public DbSet<ExampleItem> ExampleItemEntries { get; set; }
}
Your connection string contains 'User Instance=True'. This means that SQLEXPRESS uses a user instance to store your data. This is a completely different instance of SQL Server that contains a new set of databases.
I assume the code in WebRole.cs is run in a different user account than the code in ExampleController. When the ExampleController is run under a user account that is not an administrator, a user instance is used...
So when you remove 'User Instance=True' from your connectionstring and assign the proper access rights to your SQLEXPRESS database instance, that would solve the problem.
In CodeFirst Model you should define the connection string in the web.config first as below:
<connectionStrings>
<add name="ExampleDbConnection"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;
database=ExampleDb;
AttachDBFilename=|YouDataDirectory|yourdb.mdf;
User Instance=true"
providerName="System.Data.SqlClient" />
<connectionStrings/>
The DbContext class constructor accepts a name-value pair specifiying connection-string name in web.config. So you can reference this connection string in your context:
class ExampleDb : DbContext
{
public ExampleDb() : base("name=ExampleDbConnection") { }
...
}
This code does work fine in a ASP.NET MVC Web Role so you can try as above.

Categories