简体   繁体   English

如何在.NET Core中还原SQL Server备份

[英]How to restore a SQL Server backup in .NET Core

I want to restore a SQL Server database ( .bak ) using .NET Core. 我想使用.NET Core还原SQL Server数据库( .bak )。 Here is my empty website on GitHub so you can see the current config. 这是我在GitHub上的空网站,所以你可以看到当前的配置。

Restoring a database is fairly simple in the full .NET Framework - as can bee seen here . 在完整的.NET Framework中恢复数据库非常简单 - 这可以在这里看到。

Is there a way to do it from .NET Core directly, or will I need to reference the .NET Framework and use a .NET Framework class library? 有没有办法直接从.NET Core中执行此操作,还是需要引用.NET Framework并使用.NET Framework类库?

No matter how I try, I can't get it to work. 无论我如何尝试,我都无法让它发挥作用。

EDIT 编辑

I tried adding SQLManagementObject, but can't. 我尝试添加SQLManagementObject,但不能。 I'm on .NET Core 2.0. 我在.NET Core 2.0上。

在此输入图像描述

EDIT 2 编辑2

Our old projects are largely ADO.NET. 我们的旧项目主要是ADO.NET。 They use (extensively) the following DLL's that I cannot bring into my .NET Core Project: 他们(广泛地)使用以下DLL,我无法将其带入我的.NET核心项目:

  • Microsoft.SqlServer.ConnectionInfo Microsoft.SqlServer.ConnectionInfo
  • Microsoft.SqlServer.Smo Microsoft.SqlServer.Smo
  • Microsoft.SqlServer.SmoExtended Microsoft.SqlServer.SmoExtended
  • Microsoft.SqlServer.Management.Sdk.Sfc Microsoft.SqlServer.Management.Sdk.Sfc

UPDATE : With .Net Core 2.0 you can use Microsoft.SqlServer.SqlManagementObjects (140.17265.0). 更新 :使用.Net Core 2.0,您可以使用Microsoft.SqlServer.SqlManagementObjects(140.17265.0)。 SQL Server Management Objects (SMO) Framework You can use SQL SMO under Windows and Linux. SQL Server管理对象(SMO)框架您可以在Windows和Linux下使用SQL SMO。

Microsoft.SqlServer.SqlManagementObjects depends on System.Data.SqlClient (4.5.0) Microsoft.SqlServer.SqlManagementObjects依赖于System.Data.SqlClient(4.5.0)

Simple SMO backup example: 简单的SMO备份示例:

            ServerConnection serverConnection = new ServerConnection("192.168.1.1", "user", "password");
            Server server = new Server(serverConnection);
            Database database = server.Databases["AdventureWorks"];
            Backup backup = new Backup();
            backup.Action = BackupActionType.Database;
            backup.BackupSetDescription = "AdventureWorks - full backup";
            backup.BackupSetName = "AdventureWorks backup";
            backup.Database = "AdventureWorks";

            BackupDeviceItem deviceItem = new BackupDeviceItem("AdventureWorks_Full_Backup.bak", DeviceType.File);
            backup.Devices.Add(deviceItem);
            backup.Incremental = false;
            backup.LogTruncation = BackupTruncateLogType.Truncate;
            backup.SqlBackup(server);

In .NetCore to backup/restore SQL Server database you can use common ADO.NET SqlConnection and SqlCommand objects. 在.NetCore备份/恢复SQL Server数据库中,您可以使用常见的ADO.NET SqlConnection和SqlCommand对象。 To customize backup/restore you need know the syntax of T-SQL BACKUP/RESTORE statements. 要自定义备份/还原,您需要了解T-SQL BACKUP / RESTORE语句的语法。 Please consult with 请咨询

RESTORE Statements (T-SQL) RESTORE语句(T-SQL)

BACKUP Statements (T-SQL) 备份语句(T-SQL)

using System;
using System.Data;
using System.Data.SqlClient;

namespace BackupRestore
{
    class Program
    {
        static void Main(string[] args)
        {
            BackupDatabase("test", @"C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\test.bak");
            RestoreDatabase("test", @"C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\test.bak");
        }

        private static void RestoreDatabase(string databaseName, string backupPath)
        {
            string commandText = $@"USE [master];
    ALTER DATABASE [{databaseName}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
    RESTORE DATABASE [{databaseName}] FROM DISK = N'{backupPath}' WITH FILE = 1, NOUNLOAD, REPLACE, STATS = 5;
    ALTER DATABASE [{databaseName}] SET MULTI_USER;";

            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder
            {
                DataSource = "localhost",
                InitialCatalog = "master",
                IntegratedSecurity = true
            };
            using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ConnectionString))
            {
                connection.Open();
                connection.InfoMessage += Connection_InfoMessage;
                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandText = commandText;
                    command.CommandType = CommandType.Text;
                    command.ExecuteNonQuery();
                }
            }
        }

        private static void BackupDatabase(string databaseName, string backupPath)
        {
            string commandText = $@"BACKUP DATABASE [{databaseName}] TO DISK = N'{backupPath}' WITH NOFORMAT, INIT, NAME = N'{databaseName}-Full Database Backup', SKIP, NOREWIND, NOUNLOAD,  STATS = 10";

            SqlConnectionStringBuilder connectionStringBuilder = new SqlConnectionStringBuilder
            {
                DataSource = "localhost",
                InitialCatalog = "master",
                IntegratedSecurity = true
            };
            using (SqlConnection connection = new SqlConnection(connectionStringBuilder.ConnectionString))
            {
                connection.Open();
                connection.InfoMessage += Connection_InfoMessage;
                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandText = commandText;
                    command.CommandType = CommandType.Text;
                    command.ExecuteNonQuery();
                }
            }
        }

        private static void Connection_InfoMessage(object sender, SqlInfoMessageEventArgs e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

To RESTORE a database with new name for example newtest , you need execute next statement 要使用新名称(例如newtest)恢复数据库,需要执行next语句

RESTORE DATABASE [newtest] 
FROM  DISK = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup\test.bak' WITH  FILE = 1,  
MOVE N'test' TO N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\newtest.mdf',  
MOVE N'test_log' TO N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\DATA\newtest_log.ldf',  NOUNLOAD,  STATS = 5

You should not use SMO, SMO is created for those that would like to manage SQL server in a "manage SQL server type application", you're bound to run into versioning issues that you would not have when using simple TSQL commands. 您不应该使用SMO,为那些想要在“管理SQL服务器类型应用程序”中管理SQL Server的人创建SMO,您必然会遇到使用简单TSQL命令时不会遇到的版本问题。 TSQL commands work quite well on .net Core. TSQL命令在.net Core上运行良好。

One thing I'd like to mention is that you're opening your application to some troubling permissions. 我想提到的一件事是你正在打开你的应用程序以获得一些令人不安的权限。

  1. you need to set your database into single user mode before you can restore your database when you do that your web-user will be able to continue doing what it is doing (update, delete, insert) all this will alter the transaction log and will mess-up something (opt-out of some legal option, do a payment, cancel something...). 您需要将数据库设置为单用户模式,然后才能恢复数据库,当您这样做时,您的Web用户将能够继续执行它正在执行的操作(更新,删除,插入)所有这些将改变事务日志并将弄乱一些东西(选择退出一些合法选项,付款,取消某些东西......)。
  2. Are you happy with the web user being able to set it in single user mode or restore a database, could be quite malicious? 您是否满意Web用户能够在单用户模式下设置或恢复数据库,可能是非常恶意的?
  3. The web user will need elevated privileges to be able to pull this off, I can imagine someone using this to backup a database to a public folder and just grab if of your web server. Web用户需要提升权限才能将其关闭,我可以想象有人使用此权限将数据库备份到公用文件夹,然后抓住您的Web服务器。 Our Firewall logs show this type of attack vector on a daily basis ("they" do not know we do not use this). 我们的防火墙日志每天都会显示这种类型的攻击媒介(“他们”不知道我们不使用它)。

if you need to restore your database you perhaps pass this over to another task set up for this. 如果您需要恢复数据库,您可能会将其传递给另一个为此设置的任务。 you can then have this "pooling task" deal with this. 然后你可以用这个“汇集任务”处理这个问题。

Let assume you accept my concerns mentioned above (not a compleat list) and you would entertain the idea that you would like to offload this I would suggest you use a Task in SQL server for this. 假设你接受我上面提到的问题(不是完整列表),你会觉得你想要卸载这个我建议你在SQL服务器中使用一个任务。 You can schedule these tasks to run ever ... second/ minute/ day even loop them. 您可以安排这些任务运行...第二/分钟/天甚至循环它们。

You can have "N" steps in a task, 1 Step you use to "test for the restore condition" he following steps you use to do the restore in a managed way, when you're done you update a log/ send a mail etc. 您可以在任务中执行“N”步骤,1步骤用于“测试还原条件”他执行以下步骤,您可以使用以托管方式执行还原的步骤,当您完成更新日志/发送邮件时等等

When using a task you can run it using a user with the appropriate rights and when setting the database in single user mode your website will lose its connection and will be forced to wait for the restore job to restore the database state. 使用任务时,您可以使用具有相应权限的用户运行该任务,并且在单用户模式下设置数据库时,您的网站将失去其连接,并将被迫等待还原作业恢复数据库状态。

For you to be able to use SQL jobs you will need to make sure that this is activated on the server. 为了能够使用SQL作业,您需要确保在服务器上激活它。

As per the content of your task, the TSQL statement if you would like to could look something like this, please note you need to validate that the backup file reported by SQL server actually exists, this used master.sys.xp_cmdshell for that: 根据您的任务内容,TSQL语句,如果您希望看起来像这样,请注意您需要验证SQL Server报告的备份文件是否确实存在,这使用了master.sys.xp_cmdshell:

USE Master; 
GO  
SET NOCOUNT ON 

-- 1 - Variable declaration 
DECLARE @dbName sysname 
DECLARE @backupPath NVARCHAR(500) 
DECLARE @cmd NVARCHAR(500) 
DECLARE @fileList TABLE (backupFile NVARCHAR(255)) 
DECLARE @lastFullBackup NVARCHAR(500) 
DECLARE @lastDiffBackup NVARCHAR(500) 
DECLARE @backupFile NVARCHAR(500) 

-- 2 - Initialize variables 
SET @dbName = 'Customer' 
SET @backupPath = 'D:\SQLBackups\' 

-- 3 - get list of files 
SET @cmd = 'DIR /b "' + @backupPath + '"'

INSERT INTO @fileList(backupFile) 
EXEC master.sys.xp_cmdshell @cmd 

-- 4 - Find latest full backup 
SELECT @lastFullBackup = MAX(backupFile)  
FROM @fileList  
WHERE backupFile LIKE '%.BAK'  
   AND backupFile LIKE @dbName + '%' 

SET @cmd = 'RESTORE DATABASE [' + @dbName + '] FROM DISK = '''  
       + @backupPath + @lastFullBackup + ''' WITH NORECOVERY, REPLACE' 
PRINT @cmd 

-- 4 - Find latest diff backup 
SELECT @lastDiffBackup = MAX(backupFile)  
FROM @fileList  
WHERE backupFile LIKE '%.DIF'  
   AND backupFile LIKE @dbName + '%' 
   AND backupFile > @lastFullBackup 

-- check to make sure there is a diff backup 
IF @lastDiffBackup IS NOT NULL 
BEGIN 
   SET @cmd = 'RESTORE DATABASE [' + @dbName + '] FROM DISK = '''  
       + @backupPath + @lastDiffBackup + ''' WITH NORECOVERY' 
   PRINT @cmd 
   SET @lastFullBackup = @lastDiffBackup 
END 

-- 5 - check for log backups 
DECLARE backupFiles CURSOR FOR  
   SELECT backupFile  
   FROM @fileList 
   WHERE backupFile LIKE '%.TRN'  
   AND backupFile LIKE @dbName + '%' 
   AND backupFile > @lastFullBackup 

OPEN backupFiles  

-- Loop through all the files for the database  
FETCH NEXT FROM backupFiles INTO @backupFile  

WHILE @@FETCH_STATUS = 0  
BEGIN  
   SET @cmd = 'RESTORE LOG [' + @dbName + '] FROM DISK = '''  
       + @backupPath + @backupFile + ''' WITH NORECOVERY' 
   PRINT @cmd 
   FETCH NEXT FROM backupFiles INTO @backupFile  
END 

CLOSE backupFiles  
DEALLOCATE backupFiles  

-- 6 - put database in a useable state 
SET @cmd = 'RESTORE DATABASE [' + @dbName + '] WITH RECOVERY' 
PRINT @cmd 

A safer way to do this is to query the server and hope the location is valid: 更安全的方法是查询服务器并希望该位置有效:

SELECT
    bs.database_name,
    bs.backup_start_date,
    bmf.physical_device_name
FROM
    msdb.dbo.backupmediafamily bmf
    JOIN
    msdb.dbo.backupset bs ON bs.media_set_id = bmf.media_set_id
WHERE
    bs.database_name = 'MyDB'
ORDER BY
    bmf.media_set_id DESC;

both methods will fail if the source is on tape or hosted in an Amazon or Microsoft cloud. 如果源位于磁带上或托管在AmazonMicrosoft云中,则这两种方法都将失败。

It looks like the answer is in the comments: 看起来答案在评论中:

https://www.nuget.org/packages/Microsoft.SqlServer.SqlManagementObjects in the Dependencies section lists ".NETCoreApp 2.0" meaning it is a .NET Core assembly. “依赖关系”部分中的https://www.nuget.org/packages/Microsoft.SqlServer.SqlManagementObjects列出了“.NETCoreApp 2.0”,这意味着它是一个.NET核心程序集。 Since it depends on https://www.nuget.org/packages/System.Data.SqlClient/ and that depends on https://www.nuget.org/packages/Microsoft.Win32.Registry/ it'll only work on Windows, though it will work on .NET Core. 因为它取决于https://www.nuget.org/packages/System.Data.SqlClient/ ,这取决于https://www.nuget.org/packages/Microsoft.Win32.Registry/它只能用于Windows,虽然它可以在.NET Core上运行。

Alternatively, use T-SQL statements executed through SqlCommand. 或者,使用通过SqlCommand执行的T-SQL语句。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM