Web.config configuration for EF Migrations - web-config

I am implementing Code-First Migrations on my project and want to not have to use Add-Migration and Update-Database all the time in the Package Manager Console. I'd like for the updates to the database to happen automatically.
For this reason I updated my web.config file to do this. I deleted my database, but for some reason when I fire up the application, it does not create the database. Am I doing something wrong?
Here's my web.config
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<contexts>
<context type="AuctionService.DataAccess.AuctionContext, AuctionService.DataAccess">
<databaseInitializer type="System.Data.Entity.MigrateDatabaseToLatestVersion`2[[AuctionService.DataAccess.AuctionContext, AuctionService.DataAccess], [AuctionService.DataAccess.Migrations.Configuration, AuctionService.DataAccess]], EntityFramework">
</databaseInitializer>
</context>
</contexts>
</entityFramework>
EDIT
My code is in a WCF service and when I debugged this service I got this
The server encountered an error processing the request. The exception
message is 'Unable to update database to match the current model
because there are pending changes and automatic migration is disabled.
Either write the pending model changes to a code-based migration or
enable automatic migration. Set
DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable
automatic migration.'

Try ensuring you have set the AutomaticMigrationsEnabled property to true in the constructor of your AuctionService.DataAccess.Migrations.Configuration class.
Once that is going, you may also get an exception if there's potential data loss; you can ignore this by setting the AutomaticMigrationDataLossAllowed property to true.
For example:
internal sealed class Configuration : DbMigrationsConfiguration<AuctionContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
// AutomaticMigrationDataLossAllowed = true; // You may want this also, but be careful.
}
}
I'm not sure if you can set this in the .config file (can't find documentation on this).
I believe that when you initially set up migrations, you can get the generated Configuration class to have that property set for you by running the command Enable-Migrations –EnableAutomaticMigrations

Related

Resolving connection string in EFv6.3 in ASP.NET Core Windows service project

I have an ASP.NET Core application running as a Windows Service. Due to project requirements, I am using Entity Framework v6.3 (as opposed to using EF Core).
I am having trouble retrieving the correct connection string when performing a migration and also upon publishing the service to a server. When running the service locally, the connection string is retrieved successfully.
As I understand it, Entity Framework 6 is supposed to retrieve connection strings from web.config or app.config files, right? Therefore, I have an app.config file containing two connection strings, e.g.
<connectionStrings>
<add name="DataContext" providerName="System.Data.SqlClient" connectionString="Server=localhost\SQLEXPRESS;[redacted]" />
<add name="CrmContext" providerName="System.Data.SqlClient" connectionString="Server=localhost\SQLEXPRESS;[redacted]" />
</connectionStrings>
In my Startup class, I have registered both database contexts, e.g.
services.AddTransient<DataContext>();
services.AddTransient<CrmContext>();
On a Razor page, when I instantiate both data contexts on my local machine I can see the correct connection string is being resolved for both contexts (by using _crmContext.Database.Connection.ConnectionString).
When I attempt to add a migration using the update-database command on my CrmContext (automatic migrations enabled), the correct connection string isn't resolved. Instead, it defaults to creating a LocalDB database using the default connection string: (localdb)\MSSQLLocalDB
How come it isn't using the connection string I have provided in my app.config file? I also a web.config file but it doesn't resolve from there either.
CrmContext.cs
public class CrmContext : DbContext
{
public CrmContext() : base("CrmContext")
{
Database.SetInitializer<CrmContext>(null);
}
public IDbSet<CustomerDetails> CustomerDetails { get; set; }
}
CrmConfiguration.cs
internal sealed class CrmConfiguration : DbMigrationsConfiguration<CrmContext>
{
public CrmConfiguration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(CrmContext context)
{
...
context.SaveChanges();
}
}
I've tried to explicitly update the CRM connection by specifying my CrmConfiguration file:
update-database -ConfigurationTypeName CrmContext
When I do this, it creates and updates the LocalDB database instead of using my connection string.
I've also tried to explicitly referencing the connection string:
update-database -ConnectionStringName "CrmContext"
This results in this error:
No connection string named 'CrmContext' could be found in the
application config file.
My CrmContext class exists within my ASP.NET Core windows application where my DataContext class exists in a separate 'Data' project (as it's shared with an ASP.NET MVC v5 application)
When I publish my service and install the application as a Windows Service, I found that it also doesn't pick up the connection strings at all from any of the config files - it again just looks for the default localdb database. As I understand, it should pick it up from my PaymentBatchProcessorService.exe.config file, right?
My PaymentBatchProcessorService.exe.config file looks like this:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="DataContext" providerName="System.Data.SqlClient" connectionString="redacted" />
<add name="CrmContext" providerName="System.Data.SqlClient" connectionString="redacted" />
</connectionStrings>
</configuration>
As per Microsoft documentation, it should be possible to load in the additional XML configuration files via the following code in the Program.cs file, but EntityFramework still didn't pick up the connection strings:
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureAppConfiguration((hostingContext, config) =>
{
var workingDirectoryPath = Environment.GetEnvironmentVariable(EnvironmentVariables.ServiceWorkingDirectory);
config.AddXmlFile(Path.Combine(workingDirectoryPath, "app.config"));
config.AddXmlFile(Path.Combine(workingDirectoryPath, "web.config"));
})
e.g. in the above sample, the working directory path resolves to the location where my .exe is for the Windows Service.
Thanks for reading this far!
When you deploy your service, the .config file should instead be called servicename.exe.config. It should reside on the same folder where the service was registered with installutil. See Windows service app.config location.

Sample for Entity Framework 6 + Code First + Oracle 12c

I have a problem with a Visual Studio solution using Entity Framework 6 + Code First + Oracle 12c. I'm not sure it is properly configured, or if I missed something simple.
I tried to look for a sample project as a start, but was not able to find - google search, stackoverflow etc.
Is there a minimalistic sample project somewhere, which tries to create the database when runs?
Update: Just to make sure, I'm not asking anyone to create a sample for me. Before I'll do it, I want to make sure there is really no existing sample (which is strange for me, but very well might be the case).
I managed to create a working sample. Found some (not so) documented strange behaviors resulting in run time errors along the way.
Here is the full sample source: https://drive.google.com/file/d/0By3P-kPOnpiGRnc0OG5ZTDl6eGs/view?usp=sharing&resourcekey=0-ecT1EU81wJOQWokVDr_r9w
I created the sample with Visual Studio 2013. Used nuget to pull
EntityFramework 6.1.3
Official Oracle ODP.NET, Managed Entity Framework Driver 12.1.021
The important parts are
Program.cs
Context.cs
TestEntity.cs
App.config
I omit
packages.config
AssemblyInfo.cs
csproj, sln files
I also omit namespaces.
using System.Data.Entity;
public class Program
{
private static void Main(string[] args)
{
string connStr =
"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=***server***)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=***SERVICE***)));Persist Security Info=True;User ID=***User***;Password=***password***";
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
//Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
Context context = new Context(connStr);
TestEntity te = new TestEntity();
te.Id = 1;
te.Name = "Test1";
context.TestEntities.Add(te);
context.SaveChanges();
}
}
using System.Data.Entity;
public class Context : DbContext
{
public Context(string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
public virtual DbSet<TestEntity> TestEntities { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("OTS_TEST_EF");
modelBuilder.Entity<TestEntity>()
.Property(e => e.Id)
.HasPrecision(9, 2);
base.OnModelCreating(modelBuilder);
}
}
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("TestEntity")]
public class TestEntity
{
[Column(TypeName = "number")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public decimal Id { get; set; }
[StringLength(100)]
public string Name { get; set; }
}
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false"/>
<section name="oracle.manageddataaccess.client"
type="OracleInternal.Common.ODPMSectionHandler, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
<entityFramework>
<!--<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>-->
<providers>
<!--<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>-->
<provider invariantName="Oracle.ManagedDataAccess.Client"
type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</providers>
</entityFramework>
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.ManagedDataAccess.Client"/>
<add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver"
type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.121.2.0, Culture=neutral, PublicKeyToken=89b483f429c47342"/>
</DbProviderFactories>
</system.data>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<publisherPolicy apply="no"/>
<assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral"/>
<bindingRedirect oldVersion="4.121.0.0 - 4.65535.65535.65535" newVersion="4.121.2.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<!--<oracle.manageddataaccess.client>
<version number="*">
<dataSources>
<dataSource alias="SampleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=INFOTEST))) "/>
</dataSources>
</version>
</oracle.manageddataaccess.client>-->
<!--<connectionStrings>
<add name="OracleDbContext" providerName="Oracle.ManagedDataAccess.Client"
connectionString="Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = INFOTEST)));Persist Security Info=True;User ID=user;Password=password"/>
</connectionStrings>-->
</configuration>
The strange thing I found on the way:
Adding any of the following TypeNames will result in "Sequence contains no matching element" error.
/*[Column(TypeName = "numeric")]*/
/*[Column(TypeName = "number(18,0)")]*/
/*[Column(TypeName = "number(18,2)")]*/
Indicating precision with scale 0
modelBuilder.Entity<TestEntity>().Property(e => e.Id).HasPrecision(9, 0);
Will result in
Schema specified is not valid. Errors:
(7,12) : error 2019: Member Mapping specified is not valid. The type 'Edm.Decimal[Nullable=False,DefaultValue=,Precision=9,Scale=0]' of member 'Id' in type 'EF6_Oracle12c_CF.TestEntity' is not compatible with 'OracleEFProvider.number
Omitting the
modelBuilder.HasDefaultSchema("OTS_TEST_EF");
line will result in
ORA-01918: user does not exists
It is also happened that I got
ORA-00955: name is already being used by existing object
or
Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations.
I managed to overcome those by enabling the
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
line, instead of the DropCreateDatabaseIfModelChanges mode.
This has the a good sample if you are still interested . It is available on 11 g .
http://www.oracle.com/webfolder/technetwork/tutorials/obe/db/dotnet/CodeFirst/index.html
Here's a link to a sample from Oracle on using EF Code First, Migration and Visual Studio.
Oracle Learning Library on EF Code First and Code First Migration
I'm actually almost finishing up a project that uses VS, 12c and EF and the link was a good starting point. There was no particular issue about 12c that I saw.
I have a test project on github that I used to try out examples of EF6 migrations on Oracle. The code that works for me (to programatically execute all pending migrations) is here. My use case is likely common - I need to be able to deploy my application to various environments and data centres and have it do "the right thing" to work with the environment's copy of my application database.
The important bit is
//Arrange
Configuration config = new Configuration();
DbMigrator migrator = new DbMigrator(config);
Console.WriteLine("Migrating...");
foreach (string s in migrator.GetPendingMigrations())
{
//Act
Console.WriteLine("Applying migration {0}", s);
Action act = () => migrator.Update(s);
//Assert
act.ShouldNotThrow();
}
I spent days fixing this issue... Finally I solved it:
The table did not exist. I checked many times and refreshed, but the problem was not in the table itself, it was with the sequence. Every table in Oracle creates a sequence object to increase the id. So, if you delete the table make sure to drop the sequence as well, otherwise when you migrate again, it will give you ORA-00955: name is already used by an existing object.
So, the real problem is in the sequence, not in the table. But you cannot create new sequence because it already exists. It is not deleted when you delete the table, it should be deleted manually.
I hope this will help someone.

connectionString defaulting to production database.. Entity Framework

I am learning asp.net mvc 4 on top of entity framework. There is a project at work I took over and I am trying to centralize the connection credentials depending on the environment (dev, test, prod) the application is in.
Currently I have the connectionstring dynamic, but for some reason entity framework ignores the connection string initial Catalog setting.
<connectionStrings>
<add name="name1" connectionString="metadata=res://*/Model.csdl|res: //*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="Data Source=001\;Initial Catalog=**;Integrated Security=False;User ID=**;Password=**;MultipleActiveResultSets=True;Application Name=EntityFramework"" providerName="System.Data.EntityClient" />
<add name="name2" connectionString="metadata=res://*/Entites.csdl|res://*/Entites.ssdl|res://*/Entites.msl;provider=System.Data.SqlClient;provider connection string="data source=001\;Persist Security Info=True;User ID=**;password=**;multipleactiveresultsets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I have no idea what half of the stuff in the connectionString means, but it is the second connection string giving me troubles, "name2"
Running the debugger shows the base class that extends the ObjectContext called like so,
: base("name=name2", "name2")
I figured Initial Catalog was already set in the connectionstring, "name1" and that would transfer to the name2.. but for the heck of it I added the Initial Catalog to the second connection string and it still defaults to the wrong catalog. I am connecting to the same database server but we have a test and a production database..
What could be overriding this catalog setting and redirecting to the wrong database? When I run my code, I get an innerexception telling me the username (the test database username) doesn't have access to the production database, but I am not sure why the production database is being passed in.
Here is the exception:
The server principal "testuser" is not able to access the database "ProductionName" under the current security context.]
initializing ObjectContext
public Entities() : base("name=name2", "name2")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
This is also in the web.config files:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
Something else interesting I noticed. When I leave the Initial Catalog setting in on the "name2" connectionstring, and set to the test database, and all the credentials are correct, I get the original error as I posted. If I change the initial Catalog to the production name and leave the wrong credentials to log in, I get a log in failed error. Same if I change the credentials around and leave the test database in for the initial catalog. So it seems it's authenticating properly, but something else is a factor once the connection goes through?
For anyone else who stumbles across this problem. I finally figured it out. The other developer was referring to the production database explicitly in all of the stored procedures. I took out all the references and left the implicit call using the "use" statement that was injected implicitly during the export/import process..
Example:
USE [TestDatabase] <---- this goes at top of procedure
Here was an explicit call to the production database:
FROM [productionDB].[dbo].[Table] table
just make it an implicit call like so:
FROM [dbo].[Table] table
If my solution is not the answer for you, I also stumbled across this bug in sql server 2008:
https://connect.microsoft.com/SQLServer/feedback/details/354291/the-server-principal-is-not-able-to-access-the-database-under-the-current-security-context-microsoft-sql-server-error-916

Entity framework 6 without config file?

I have an application that can not use a config file and has to set up the connectionstring for the entity context by code (with EntityConnectionStringBuilder).
The problem comes however with this:
No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlClient'.
Since I can not use the standard app.config file, am I screwed in EF6? It was not a problem in EF4 if I recall correctly.
So the settings inside the entityFramework-tag is something I wish to set in code.
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="v11.0" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
I'm using EF 6 without an App.config file at all I just pass a connection string to my DBContext (well the connection is read out of a config file elsewhere but that's up to you). Just Remove all the EF stuff from the config file.
Here's how I got it to work.
public partial class MyDbContext : DbContext, IMyDbContext
{
public MyDbContext(string connectionString,
DbValidationMode validationMode = DbValidationMode.Enabled,
DbLazyLoadingMode lazyLoadingMode = DbLazyLoadingMode.Disabled,
DbAutoDetectMode autoDetectMode = DbAutoDetectMode.Enabled)
: base(((EntityConnectionStringBuilder)new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlClient",
ProviderConnectionString = connectionString,
Metadata = #"res://*/Contexts.Test.MyModel.csdl|res://*/Contexts.Test.MyModel.ssdl|res://*/Contexts.Test.MyModel.msl"
}).ToString())
{
this.Configuration.ValidateOnSaveEnabled = validationMode.Equals(DbValidationMode.Enabled);
this.Configuration.LazyLoadingEnabled = lazyLoadingMode.Equals(DbLazyLoadingMode.Enabled);
this.Configuration.AutoDetectChangesEnabled = autoDetectMode.Equals(DbAutoDetectMode.Enabled);
}
... Etc
Then I just inject this context into all my services.
I'm using Database First design so I found it easier to modify the T4 Templates.
There may be nicer ways of doing this but I've not ran into any problems at all.
In EF6 you can use Code-based Configuration for Entity Framework specific setup. (Also see How to add entity framework 6 provider in code?). Then you can build connection string and pass it to the ctor of the context.

EF5 Code First Migration problems publishing to IIS

I've created a MVC 4 project which uses EF5 Code First with migrations.
Because I was new to this topic I used the following article.
Now that the development is finished I want to publish to IIS (I use FTP or Web deployment package). So before publishing I changed the connectionstring to the right db server.
But after publishing the site I get an exception when accessing pages which make use of the DB. The exceptions refers to the fact that he can't connect to the database.
Because of these problems I decided to try it out locally on another DB server than the default one "(LocalDB)\v11.0". BTW: "(LocalDB)\v11.0" works like a charm...
While debugging I got a better look at the error.
Here is an image of the error:
What I've already tried:
Generate a sql script by executing "Update-Database -Script
-SourceMigration:$InitialDatabase" in the Package manager console. After I ran this script on the dbserver to create the db. Tables were
created but the error was still there.
I changed my connectionstring to all kinds of combination with no
results
I already used a custom user for the app pool in ISS and gave this user full rights to the DB server and the db.
Here is the most important part of my web.config:
<connectionStrings>
<add name="DefaultConnection" providerName="System.Data.SqlClient" connectionString="Data Source=LOCALHOST\MSSQLSERVER;Initial Catalog=ProjectX;Integrated Security=TRUE;MultipleActiveResultSets=True" />
</connectionStrings>
And
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=LOCALHOST\MSSQLSERVER; Integrated Security=True; MultipleActiveResultSets=True" />
</parameters>
</defaultConnectionFactory>
</entityFramework>
My DBCcontext class constructor looks like
public DBContext(): base("DefaultConnection")
{
}
I guess I am missing something, this is the first time I use EF Code First with migrations.
This problem is really driving me crazy. I am out of ideas.
Just found out that the problem was caused by the connectionstring.
The string was incorrect, seems like you if you have a default SQL Server you just need to use
"Data Source=LOCALHOST".
I guess because of all the problems I had that day with the deployment i overlooked the easy parts. Yust make sure you the following things are true when you have problems like I did:
Your connectionstring has the same name as your DBContext. Another sollution could be to do like i did and add the connectionstring name to the base:
public DBContext(): base("DefaultConnection")
{
}
If you also have the defaultconnectionfactory set. Make sure to also update the Data Source there. This was one of the problems I struggled with. I didn't check the bottom of my web.config ...
If the problem still persists you can use EF profiler to have a look at the connectionstring when your app of site is accessing the DB.