如何在代码中分离本地DB(SQL Server Express)文件

12
3个回答

13

我不得不从几个地方拼凑出答案,所以我将在这里发布它:请注意,在通过SQL Server对象资源管理器进行手动分离之前,可以通过手动删除Visual Studio中的.mdf文件来手动分离。

''' <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

12

我遇到了同样的问题,一直在思考如何处理它。

有三种方法:

  1. 在完成(或在工作期间)与数据库交互后分离连接

    我没有找到在LinqToSQL中关闭连接的方法,但实际上也不需要。只需执行以下代码:

 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);
 }

并确保在之后没有任何尝试查询db的操作(否则它会再次被附加)。

  • 在启动时分离

    在连接到db之前,分离很简单:

  •  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);
    

    这个套装非常适合我的需求,因为我不在意启动应用程序的延迟(因为在这种情况下我将始终附加到db),但它可以修复任何类型的

    System.Data.SqlClient.SqlException (0x80131904):数据库'c:\blablabla\database1.mdf'已经存在。选择一个不同的数据库名称。

    如果数据库文件被删除并且您尝试以编程方式创建它,则会出现此问题

     // DataContext
     if (!DatabaseExists())
         CreateDatabase();
    
  • 另一种方法

    您还可以像这样运行命令行工具 sqllocaldb

  •  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();
    

    它将停止服务器并分离所有数据库。如果您有其他使用LocalDB的应用程序,则它们在下次尝试查询时将遇到附加延迟。


    1
    对于“启动时分离”,我收到以下信息:“用户没有权限更改数据库'@p0',数据库不存在或数据库处于不允许访问检查的状态。ALTER DATABASE语句失败。”有什么想法吗? - florians
    @fschricker,是的。您在启动时没有分离。数据库已经在您的应用程序中某个地方打开了。 - Sinatr
    我在我的单元测试 [ClassInitialize] 中运行代码,所以我假设数据库已关闭(FYI:使用sqllocaldb正常工作)。 但是我通过MS SQL Server Mgmt Studio观察了localdb,也许那个工具有一个打开的连接? - florians

    1

    以下是我的EntityFramework Core 1.0的解决方案:

    正如您所看到的,可以使用数据库名称及其完整文件路径。

    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}'");
    }
    

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接