I'm using Entity Framework Code First migrations (with Sql Server). For my tests, I create a test database for each execution (deleting it if exists):
// Is called once before any test is run.
[SetUpFixture]
public class Setup
{
[SetUp]
public void Init()
{
Database.SetInitializer(new TestDatabaseInitializer());
}
// ...
}
public class TestDatabaseInitializer : DropCreateDatabaseAlways<MyDbContext>
{
MyDbContext _context;
public override void InitializeDatabase(MyDbContext context)
{
_context = context;
if (context.Database.Exists())
{
// Remove database...
}
base.InitializeDatabase(context);
}
// ..
}
And the connection string for my test:
<connectionStrings>
<add name="TaskRequirementsDb" connectionString="Data Source=(localdb)\v12.0; Initial Catalog=db_test; Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
This works fine in my dev enviroment. So far no problem.
Now, I have a build in VSTS where I want to run integrated tests with a database. Is it possible? I read it is, because VSTS build servers come with MSSQL Server 2012 and MSSQL Server 2014 preinstalled (I'm using Hosted agent).
The problem is, what connection string should I use?
Note: I have already read this question:
Database integration tests in Visual Studio Online
But I don't know how apply this solution to my problem.
Edit
I've added a command line step (before running tests task) to create a localDb instance:
"%ProgramFiles%\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" create "v12.0" 12.0 -s
It is executed properly:
[command]"%ProgramFiles%\Microsoft SQL Server\120\Tools\Binn\SqlLocalDB.exe" create "v12.0" 12.0 -s
LocalDB instance "v12.0" created with version 12.0.2000.8.
LocalDB instance "v12.0" started.
But the result is the same. I'm getting the following error when tests are executed:
[error] System.Data.SqlClient.SqlException: CREATE DATABASE permission denied in database 'master'.
Related
I am creating a small app with EF code first and I want to call the update database command from the package manager console and target the database in my app.config which is a local .mdf.
I have this connection string in my app.config
<connectionStrings>
<add name="EventsConnectionString"
connectionString="Data Source=(localdb)\v11.0;Database=EventsApp;Trusted_Connection=Yes;" />
</connectionStrings>
RegistrantContext class with connection string in constructor
using System.Data.Entity;
using EventsApp.Entities;
namespace EventsApp.Contexts.DataContexts
{
public class RegistrantDb :DbContext
{
public RegistrantDb()
: base("EventsConnectionString")
{
}
public DbSet<Registrant> Registrants { get; set; }
}
}
My file structure
And the command to update the database:
Update-Database -ConfigurationTypeName EventsApp.Contexts.DataContexts.RegistrantMigrations.Configuration -verbose
Error message
Error Number:-1,State:0,Class:20
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
I believe my settings are wrong so it can't find Events.mdf. Does anyone know what I need to change?
You should always check if you use the correct project to apply updates to (either select the correct project from the "Default Project" dropdown at the top of the package manager console or you can add -ProjectName to your Update-Database command:
Update-Database -ProjectName EventsApp.Contexts -YourOtherOptions
VS2013 WebAPI 2.x with Repository has suddenly begin to look for data migrations to happen on a database instance other than the one it has been working with for the past 3 months - EF version 6
I have SQL Server 2012 (v11.0.2218.0) as ron-hp\localdb - this has accepted 12 migrations with add-migration/update-database commands for 3 months
As of yesterday: going to update-database yields message that
PM> update-database -verbose
Using StartUp project 'PartyPoochesClient'.
Using NuGet project 'PartyPooches.Repository'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'PartyPooches.Repository.Entities.PartyPoochesContext' (***DataSource: (localdb)\v12.0,*** Provider: System.Data.SqlClient, Origin: Convention).
I have never had an instance of v12.0 and only as of yesterday's migration / update-database attempt PM is expecting to see a (localdb)\v12.0 to accept the update. Any code search entire solution for a (localdb)\v12.0 yields nothing. As expected it times out not able to locate such an instance with SQL Server error 50, the DB, which the project created with CodeFirst, has almost 12 Migration updates to the ron-hp\localdb instance without issue.
The code:
internal sealed class Configuration : DbMigrationsConfiguration<PartyPooches.Repository.Entities.PartyPoochesContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "PartyPooches.Repository.Entities.PartyPoochesContext";
}
protected override void Seed(PartyPooches.Repository.Entities.PartyPoochesContext context)
The config:
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
<parameters>
<parameter value="Data Source=ron-hp\localdb;Initial Catalog=PartyPooches.Repository.PartyPoochesContext; user=xxxxx;password=xxxxx; MultipleActiveResultSets=True;App=EntityFramework"/>
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/>
</providers>
</entityFramework>
The DbContext
public class PartyPoochesContext : DbContext, IDisposable
{
public DbSet<Dog> Dogs { get; set; }
public DbSet<Handler> Handlers { get; set; }
public DbSet<Skill> Skills { get; set; }
public DbSet<DogType> DogTypes { get; set; }
public DbSet<Schedule> Schedules { get; set; }
public DbSet<Appointment> Appointments { get; set; }
public DbSet<PaymentType> PaymentTypes { get; set; }
public DbSet<Customer> Customers { get; set; }
The settings above have seen this SQL Server 2012 instance shown for 3 months.
No changes made to settings, but a recent entity change change has been implemented for a minor database update which is now looking to a non-existence instance of SQL Server. Flawless for 3 months until yesterday. Unable to locate any internet-based information dealing with this. Acts like some NuGet package slipped something in but not certain of that.
The key to the source of your issue is here: Origin: Convention. the <parameter value="DataSource=..." for Entity Framework is not actually the project's database connection string. It is the parameter being supplied to your application's ConnectionFactory when the app creates a new DbContext. However, any other connections outside Entity Framework when the app is running, or Entity Framework itself when the app is not running (for example, migrations) expect a traditional ConnectionString key in the web.config.
When you attempt to perform an update-database and there is no ConnectionString value present, Entity Framework uses convention to decide upon a connection string to use. This convention is based on many factors, including the version of software installed on your PC. If you only have SQL LocalDb 2012 installed on your machine (the standard with earlier releases of Visual Studio 2013) then the actual localdb path would be (localdb)\v11.0 by default convention. This actually stores your database in the folder %localappdata%\Microsoft\Microsoft SQL Server Local DB\Instances\v11.0 on your disk drive.
If any application on your machine updates your system to SQL LocalDb 2014, the convention changes to (localdb)\v12.0, and new databases are assumed to be put in %localappdata%\Microsoft\Microsoft SQL Server Local DB\Instances\v12.0.
Ultimately, you should provide a more complete DataSource value than localdb, using the specific path you wish to use, (localDb)\v11.0. You also should provide a <ConnectionString> value in your web.config to match your Entity Framework <Parameters> key, to ensure that you are always guaranteed to target the same database in every instance.
Also note, that instead of using the DefaultConnectionFactory, you could instead pass the name of the <ConnectionString> key to the constructor of your DbContext.
Code related info:
Refer to Entity Framework 6.13 by NuGet under Visual Studio 2013
Use database-first mode, that is, create .edmx file with Visual Studio template ADO.NET Entity Data Model -> EF Designer from database
My DbContext code:
public partial class MySampleEntities : DbContext
{
public MySampleEntities ()
{
}
public MySampleEntities (string nameOrConnectionString)
: base(nameOrConnectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
...
}
One method to modify model with below sample code:
using (var dbContext = GetDbContext())
{
...
dbContext.Entry(blobItem).State = EntityState.Modified;
await dbContext.SaveChangesAsync();
}
Unit Test Cases info:
Use NUnit and Moq
Some Unit Test code:
var mockContext = new Mock<MySampleEntities>();
Test passed with initial database schema, after some database table column names changed, and execute Visual Studio "Update Model from Database..." command on .edmx diagram, update all corresponding model properties, build code, and finally failed to run unit test on code dbContext.Entry(blobItem).State = EntityState.Modified with this exception:
The model backing the 'MySampleEntities' context has changed since the database was created. Consider using Code First Migrations to update the database (http://go.microsoft.com/fwlink/?LinkId=238269).
Solutions tried:
Use Database.SetInitializer(null) in constructors of MySampleEntities
Failed to execute NuGet Package Manager commands like Enable-Migrations, Update-Database etc with below exception, seems it is for code-first mode:
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.
My questions:
How to resolve such issue to make unit test case run successfully?
I have a Web API project accessing a database file in its App_Data folder. The database is created using EF Migrations.
I have some integration tests to confirm data structures and queries. They just create a Web API controller and use it to perform queries. My Test Project has an App.config file, which currently has an absolute path to the *.mdf database file (in the web api project).
This is a problem because a) I am doing my tests on the application database, and b) I have an absolute path in my App.config file.
I would like to create a test database in the test project.
Is there some way I can get Migrations to create another database (with a different Seed method) in the Test Project?
In the Web Api project's Web.config connection string we use |DataDirectory| to specify the location of the database. Is there an equivalent in a test project's App.config?
Failing all that, is there some way I can point the test project's connection string to the application db without using an absolute path?
My solution is to have a static DbManager class that does a Setup(), which I will run from the [ClassInitialize] method of the database testing classes. Setup()will:
Change the connection string according to the current AppDomain.CurrentDomain.BaseDirectory (so no longer an absolute path in App.config).
Use other AppSettings from App.config to determine which database to use, which test data set to use, and whether or not to drop and recreate the database.
Some code:
public static class DbManager
{
private static string ErrorMsg { get; set; }
private static ApplicationDbContext _db;
private static readonly Random Rdm = new Random();
public static void SetupDb()
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
bool refreshDb = Convert.ToBoolean(ConfigurationManager.AppSettings["RefreshDbInTestClassInitialization"]);
string dataSet = ConfigurationManager.AppSettings["DataSetToAddForEachTestClass"];
string dbName = ConfigurationManager.AppSettings["testDatabaseName"];
var connectionStr = config.ConnectionStrings
.ConnectionStrings["DefaultConnection"].ConnectionString
.Replace("{dbPath}", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, (dbName + ".mdf")))
.Replace("{dbName}", dbName);
config.AppSettings.SectionInformation.ForceSave = true;
config.ConnectionStrings.ConnectionStrings["DefaultConnection"].ConnectionString = connectionStr;
config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
if (refreshDb)
{
Database.Delete(connectionStr);
AddDataSet(dataSet, true);
}
}
// AddDataSet() creates a DbContext object and generates test data.
}
So the connection string in App.config looks like this:
connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename={dbPath};Initial Catalog={dbName};Integrated Security=True"
Then App.config AppSettings section has these extra key value pairs:
<add key ="RefreshDbInTestClassInitialization" value ="true"/>
<add key="DataSetToAddForEachTestClass" value="Large"/> <!--Possible values: Large, Small-->
<add key="testDatabaseName" value="testDb"/>
In my configuration I have this:
public sealed class Configuration : DbMigrationsConfiguration<App.Repository.NogginatorDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(AppDbContext context)
{
SqlConnection.ClearAllPools();
//context.Database.CreateIfNotExists();
System.Data.Entity.Database.SetInitializer(new DropCreateDatabaseAlways<AppDbContext>());
if (!WebMatrix.WebData.WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection("TestConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
}
}
This is used for a test db that should drop and recreate every time. Though when I hit "update-database" from the package manager console, even if the database is deleted manually prior to running, I get:
Cannot drop database "Nogginator.Test" because it is currently in use.
My connection string:
<add name="TestConnection"
providerName="System.Data.SqlClient"
connectionString="Data Source=.\;Initial Catalog=App.Test;Trusted_Connection=True;MultipleActiveResultSets=True;" />
Why would this be happening?
If you were recently debugging your web application, ensure that the IIS Express isn't still running and that there are no w3wp.exe processes associated with IIS Express. This process may still be holding on to a database connection.