How to detach a LocalDB (SQL Server Express) file in code - localdb

When using LocalDB .mdf files in deployment you will often want to move, delete or backup the database file.
It is paramount to detach this file first as simply deleting it will cause errors because LocalDB still keeps a registration of it.
So how is a LocalDB .mdf file detached in code?

I had to string together the answer from several places, so I wil post it here:
Mind, manually detaching the .mdf file from Visual Studio is possible after manually deleting it before detachment by going through SQL Server Object Explorer.
''' <summary>
''' Detach a database from LocalDB. This MUST be done prior to deleting it. It must also be done after a inadvertent (or ill advised) manual delete.
''' </summary>
''' <param name="dbName">The NAME of the database, not its filename.</param>
''' <remarks></remarks>
Private Sub DetachDatabase(dbName As String)
Try
'Close the connection to the database.
myViewModel.CloseDatabase()
'Connect to the MASTER database in order to excute the detach command on it.
Dim connectionString = String.Format("Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True")
Using connection As New SqlConnection(connectionString)
connection.Open()
Dim cmd = connection.CreateCommand
'--Before the database file can be detached from code the workaround below has to be applied.
'http://web.archive.org/web/20130429051616/http://gunnalag.wordpress.com/2012/02/27/fix-cannot-detach-the-database-dbname-because-it-is-currently-in-use-microsoft-sql-server-error-3703
cmd.CommandText = String.Format("ALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE", dbName)
cmd.ExecuteNonQuery()
'--
'--Now detach
cmd.CommandText = String.Format("exec sp_detach_db '{0}'", dbName)
cmd.ExecuteNonQuery()
'--
End Using
Catch ex As Exception
'Do something meaningful here.
End Try
End Sub

I had the same issue and was thinking of how to deal with it.
There are 3 approaches.
Detach at the end of (or during) working with database
I didn't find the way to close connection in LinqToSQL, but actually it is not needed. Simply execute the following code:
var db = #"c:\blablabla\database1.mdf";
using (var master = new DataContext(#"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True"))
{
master.ExecuteCommand(#"ALTER DATABASE [{0}] SET OFFLINE WITH ROLLBACK IMMEDIATE", db);
master.ExecuteCommand(#"exec sp_detach_db '{0}'", db);
}
and make sure nothing will try to query db after (or you get it attached again).
Detach on start
Before you made any connection to db, detaching is as simple as:
var db = #"c:\blablabla\database1.mdf";
using (var master = new DataContext(#"Data Source=(LocalDB)\v11.0;Initial Catalog=master;Integrated Security=True"))
master.ExecuteCommand(#"exec sp_detach_db '{0}'", db);
This suit very well to my needs, because I do not care about delay to start application (because in this case I will have to attach to db always), but it will fix any kind of
System.Data.SqlClient.SqlException (0x80131904): Database 'c:\blablabla\database1.mdf' already exists. Choose a different database name.
which occurs, if database file is delete and you try to create it programmatically
// DataContext
if (!DatabaseExists())
CreateDatabase();
Another way
You can also run command line tool sqllocaldb like this:
var start = new ProcessStartInfo("sqllocaldb", "stop v11.0");
start.WindowStyle = ProcessWindowStyle.Hidden;
using (var stop = Process.Start(start))
stop.WaitForExit();
start.Arguments = "delete v11.0";
using (var delete = Process.Start(start))
delete.WaitForExit();
It will stop the server, detaching all databases. If you have other application using LocalDB, then they will experience attaching delay next time when they try to do query.

Here is my solution for EntityFramework Core 1.0
As you see the database name can be used with its full file path.
var dbf = fileDlg.FileName;
var options = new DbContextOptionsBuilder();
options.UseSqlServer($#"Server=(localdb)\mssqllocaldb;Initial Catalog=master;MultipleActiveResultSets=False;Integrated Security=True");
using (var master = new DbContext(options.Options))
{
master.Database.ExecuteSqlCommand($"ALTER DATABASE [{dbf}] SET OFFLINE WITH ROLLBACK IMMEDIATE");
master.Database.ExecuteSqlCommand($"exec sp_detach_db '{dbf}'");
}

Related

SocketException thrown when using linq for Npgsql EntityFramework6 model

After much effort getting my MVC5 vb.net app configured with Npgsql and EntityFramework6.Npgsql I can connect to the postgres database fine using the Entity Data Model Wizard in Visual Studio 2017, creating a new connection with Data Provider of PostgreSQL Database, entering my database server details and testing the connection (succeeds). I can also double-click the EDMX file and add tables, etc as expected. This is my first project that talks to a postgreSQL database (normally use MS SQL Server). Everything seems to be happy and fine until I encounter code that is a linq statement that attempts to query the database. My Linq statement is:
Dim l_ListOfPwrCycleCrashEvents As List(Of pwr_cycle_crash_events) = (From item In m_AnalyticsEntities.pwr_cycle_crash_events Where item.serialnumber = "0123445678" Select item).ToList
I have the statement in a try/catch block, but visual studio still reports the following:
Exception thrown:'System.Net.Sockets.SocketException' in System.dll Additional
information: A non-blocking socket operation could not be completed
immediately occurred
I cannot seem to figure out why this statement fails. I am able to use similar statements against a different EntityFramework (MS SQL Server) that is also configured in the application.
The complete method that contains the linq statement:
Public ReadOnly Property iCountOfPwrCycleCrashEvents(
ByVal a_sSerialNumber As String
) As Integer Implements IAnalytics.iCountOfPwrCycleCrashEvents
Get
Try
Dim l_ListOfPwrCycleCrashEvents As List(Of pwr_cycle_crash_events) = (From item In m_AnalyticsEntities.pwr_cycle_crash_events
Where item.serialnumber = a_sSerialNumber
Select item).ToList
If (l_ListOfPwrCycleCrashEvents IsNot Nothing) Then Return l_ListOfPwrCycleCrashEvents.Count
Catch l_Exception2 As System.Net.Sockets.SocketException
Dim askjfhakjh As Integer = 7
Catch l_Exception As Exception
Dim kjhadkjh As Integer = 1
End Try
Return 0
End Get
End Property
I am using Npgsql v4.1.1 and EntityFramework6.Npgsql v6.3.0 in an application that targets .NET Framework 4.5.1.
I can't seem to figure out why the linq statement throws this exception or how to solve the problem. What suggestions do you have?
I figured out the issue. I was using 4.5.1 framework because I thought I had a dependency that would not allow me to move to 4.5.2. I went to Package Manager Console and ran the following command:
Update-Package -ProjectName myProjectName -reinstall
By doing so, I found that I had a package that was needed but could not be loaded because it required the 4.5.2 framework (or higher). I changed the framework of the app to 4.5.2 and issued the above Package Manager command and it executed without errors. I ran the app and the linq statement no longer throws an exception.

How create a database in azure elastic pool with entity framework core?

I would like to create a database with entity Framework core that would be automatically added to my azure elactic pool.
I do that with a DatabaseFacadeExtension that execute SQL command after the db creation like suggested here:
Azure SQL Server Elastic Pool - automatically add database to pool
public static async Task<bool> EnsureCreatedAsync(this DatabaseFacade databaseFacade, string elasticPoolName, CancellationToken cancellationToken = default)
{
if (!await databaseFacade.EnsureCreatedAsync(cancellationToken)) return false;
// the database has been created.
var dbName = databaseFacade.GetDbConnection().Database;
try
{
cancellationToken.ThrowIfCancellationRequested();
if (!string.IsNullOrEmpty(elasticPoolName))
{
await databaseFacade.ExecuteSqlCommandAsync(new RawSqlString(
$"ALTER DATABASE {dbName} MODIFY ( SERVICE_OBJECTIVE = ELASTIC_POOL (name = [{elasticPoolName}] ));"),
cancellationToken);
}
return true;
}
catch
{
await databaseFacade.EnsureDeletedAsync(cancellationToken);
throw;
}
}
It's works but I will prefer an atomic operation where the database would be created directly in the Azure Elastic Pool.
I had a very similar issue. Fortunately, I took cues from the previous answer and I improvised on it to arrive at a solution.
I had a common database to manage the application and whenever a new client onboards, I need to create a new database. So, I had to maintain multiple database contexts in my .NET core application. Also, I had migrations for the clientContext ready in my codebase, which just needed
client_db.Database.MigrateAsync();
to create the database. But, I couldn't create it directly under elastic pool as Azure doesn't have any default settings which support that. So, MigrateAsync always created the database outside the pool.
So, I created the database within the pool using T-SQL command from my common database context, followed by MigrateAsync() to migrate all the required schema.
var commandText = "CREATE DATABASE client1 ( SERVICE_OBJECTIVE = ELASTIC_POOL ( name = demoPool ) );";
db.Database.ExecuteSqlCommand(commandText);
clientContext client_db = new clientContext(approved_corporate.Id, _configuration);
client_db.Database.MigrateAsync();
Also I had a custom Constructor in my clientContext to support this:
public clientContext(int client_id, IConfiguration configuration = null)
{
string client_code = "client" + client_id.ToString();
connection_string = configuration["ConnectionStrings:Client"].ToString().Replace("client_code", client_code);
}
Azure Elastic Pool supports you creates a new database in an existing pool or as a single database. You must be connected to the master database to create a new database.
For more details, please see: Transact-SQL: Manage pooled databases.
Example T-SQL Code:
Creating a Database in an Elastic Pool:
CREATE DATABASE db1 ( SERVICE_OBJECTIVE = ELASTIC_POOL ( name = S3M100 ) ) ;
Please see: Azure SQL Database single database/elastic pool
You can replace the T-SQL statement and try again.
Hope this helps

Failure to find table when using multiple schemas in PostgreSQL

WPF PostgreSQL 11.1
Npgsql.PostgresException: '42P01: relation "testme" does not exist'
When attempting to use a PostgreSQL database with multiple schemas, I have defined the following connection strings in the App.config. Note that the only difference is in the SearchPath:
<system.data>
<DbProviderFactories>
<add name="Npgsql Data Provider" invariant="Npgsql" support="FF" description=".Net Framework Data Provider for Postgresql Server" type="Npgsql.NpgsqlFactory, Npgsql, Version=4.0.4.0, Culture=neutral" />
</DbProviderFactories>
</system.data>
<connectionStrings>
<clear />
<add name="localconnection" providerName="Npgsql" connectionString="Server=127.0.0.1;Port=5432;Database=chaos;User Id=postgres;Password=****;Searchpath=nova" />
<add name="phoenixconnection" providerName="Npgsql" connectionString="Server=127.0.0.1;Port=5432;Database=chaos;User Id=postgres;Password=****;SearchPath=phoenix;" />
</connectionStrings>
The Npgsql data provider was installed using NuGet: Runtime Version:
v4.0.30319 Version: 4.0.4.0
In PostgreSQL, in the Phoenix schema:
CREATE TABLE phoenix.testme
(
name text COLLATE pg_catalog."default" NOT NULL
)
WITH (
OIDS = FALSE
)
TABLESPACE pg_default;
ALTER TABLE phoenix.testme
OWNER to postgres;
Using PgAdmin, displaying the testme table works without problem:
select * from phoenix.testme;
I have configured the WCF service using the above connection strings. Using PetaPoco, I write the following script:
public string SayHello()
{
string msg;
using (var db = new chaosDB("phoenixconnection"))
{
var m = db.ExecuteScalar<string>("select version()");
msg = string.Format("Hello from {0}", m);
m = db.ExecuteScalar<string>("select current_schema");
msg = string.Format("{0} Current Schema is {1}", msg, m);
var ss = db.ExecuteScalar<string>("show search_path");
var s = db.Fetch<string>("select * from testme"); <---THIS FAILS!
msg = string.Format("{0} I Am {1}", msg, m);
}
return msg;
}
All works correctly until the "select * from testme" is executed, when I receive the above error. Note: ss from "show search_path" returns correctly with "phoenix"
WHAT AM I DOING WRONG? How do I get this to work??
Any help is most appreciated?
After much head scratching the answer became self-evident. First I had reset the search_path in the database. This did not help. Then I rebuilt the POCO's with PetaPoco and quickly discovered that not only was the new table, "testme", not created, but nor were any POCO's. So, checking, the Database.tt file in PetaPoco showed it to have the wrong ConnectionStringName. Changing the ConnectionStringName to "phoenixconnection" allowed building the POCO's, but again failed to find the "testme" table.
Then the mistake became readily apparent, as stated above, both the "phoenixconnection" and the "localconnection" were pointed to the same port. From previous development, I had PostgreSQL v10.1 running on the same port as the newer PostgreSQL v11.1. Apparently, the first PostgreSQL v10.1 was receiving the connection (and not the newer PostgreSQL v11.1).
Going to services (services.msc) and shutting down v10.1 and running Database.TT now gave the error:
System.InvalidOperationException: Sequence contains more than one matching element
Apparently v10.1 (which I was using for development) only had ONE schema, but v11.1 has multiple schemas. I take the error message to mean that PetaPoco was seeing multiple tables with the same table name--i.e.,it was not distinguishing between schemas.
So, the problem is now solved.
Fix the ports! The older single-schema PostgreSQL v10.1 is kept on port: 5432.
The newer multiple-schema PostgreSQL is kept on port 5433. The v10.1 will be used for the POCO's.
Fix the connection strings in App.config of the WCF so that at run time, the WCF will use the newer v11.1. Once generated, LEAVE THE POCO'S alone and reference them in the WCF file.
Apparently, PetaPoco, can only work with one schema in generating its POCO's, but at runtime will read the connection strings from the App.Config of the WCF to execute its queries, etc. (So in the App.config where Database.TT resides, point PetaPoco to the "development" Database having only a single schema, but in the WCF environment, point the connection string to the new database with multiple schemas. The SearchPath of the connection string IS respected when running through Npgsql).
It would be nice if PetaPoco could generate POCO's specific to a schema in a multi-schema environment, but at the moment, I guess it can't :(
Addendum Note: It turns out that a given instance of PostgreSQL can have multiple DATABASES. So if the connection string for Npgsql is specific to a development database --i.e., a database with only one schema--then during development, PetaPoco works great to create the POCO's. These POCO's can then be directly used in a WCF Service project and uploaded to IIS website. The App.config files of the web site can then be directed to use the run-time database (again in the connection string) to the deployed database. All works well! :)

Flyway - Flyway Schema migration failed

I have successfully configured spring boot with a new project to work
with flyway
Migrated with the Postgres database from the version 0001.0 to 0008.0
I have made manually alter the script in local but
flyway migration getting failed.
Sample Error message:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'flywayInitializer' defined in class path
resource
[org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]:
Invocation of init method failed; nested exception is
org.flywaydb.core.api.FlywayException: Validate failed: Migration
checksum mismatch for migration version 0006.0
How to alter the database tables without affecting flyway script from the flyway_schema_history?
For example, I need to change the table name using alter command but executing the flyway migration script without failed.
Any suggestions, Kindly appreciated.
Note:- I don't want to remove the script entries from the table flyway_schema_history.
There are a few ways to do this:-
1) Create a new script file with incremented version. Put your DDL commands to alter the table in this file. Then run migration.
2) If you don't want to delete the entry from the schema_version table, you can change the checksum value in that table. To calculate checksum, use the following method copied from org.flywaydb.core.internal.resolver.sql.SqlMigrationResolver. You can pass null for resource parameter:-
/**
* Calculates the checksum of this string.
*
* #param str The string to calculate the checksum for.
* #return The crc-32 checksum of the bytes.
*/
/* private -> for testing */
static int calculateChecksum(Resource resource, String str) {
final CRC32 crc32 = new CRC32();
BufferedReader bufferedReader = new BufferedReader(new StringReader(str));
try {
String line;
while ((line = bufferedReader.readLine()) != null) {
crc32.update(line.getBytes("UTF-8"));
}
} catch (IOException e) {
String message = "Unable to calculate checksum";
if (resource != null) {
message += " for " + resource.getLocation() + " (" + resource.getLocationOnDisk() + ")";
}
throw new FlywayException(message, e);
}
return (int) crc32.getValue();
}
3) If you are using Flyway Pro version 5+, you can rollback the migration https://flywaydb.org/getstarted/undo.
The answers here are outdated but can still help you.
It sounds like you might be in one of two situations:
You want to re-run a versioned migration. This isn't really how flyway works, as Kartik has suggested, create a new versioned migration to alter the table.
A migration file has been modified and you want to leave it that way and run new ones (eg 0009.0). In this situation you can try:
Run repair. Which will recalculate the checksums (among other things).
Turn off the validateOnMigrate option which will not fail a migration if there are modified migration files.
To solve this error locally without dropping your whole db:
Fix the migration error which caused the root problem
Disconnect your db server
Open the table "flyway_schema_history" which would be created automatically
Delete the rows with the versions that are causing the mismatch problem
Open the tables that have columns depending on the conflict migrations and drop those columns (if needed)
Run again your db server with the new migrations

SQL Timeout when running an Entity Framework Migration

I am currently experiencing a SQL Timeout when running a SQL() command inside of an EF Migration.
Situation:
I am replacing a bunch (>50) tables with one table, and need to convert the data from those tables I'm about to drop into the new table. I've organized the Migration the following way:
1.Create the new table.
In the same Migration, use the SQL() function to run a sql script that migrates the data.
3.Drop all the old tables.
Currently, the migration gives the following error:
System.Data.SqlClient.SqlException (0x80131904): Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
The statement has been terminated. ---> System.ComponentModel.Win32Exception (0x80004005): The wait operation timed out
The error is happening in an environment where I give them an installer, and they run it without me involved, so I can't manually run individual migrations, and pause in the middle to run the SQL script.
Is there any way to change the timeout for a connection, or get around this issue?
Environment:
EF 6.0 Code First
SQL Server 2012
See this answer.
Use Configuration.cs file to set custom time out:
internal sealed class Configuration :
DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "YourDbContext";
// New timeout in seconds
this.CommandTimeout = 60 * 5;
}
}
With this method, you can change the timeout only for migration and not everyone using your default connection string.
You should be able to set the connection timeout in the connection string, something like:
Connection Timeout=180;