【问题标题】:c# - Executing SQL script to transfer datac# - 执行 SQL 脚本传输数据
【发布时间】:2017-11-01 03:28:13
【问题描述】:

我正在使用 c# 编写一个程序,其中的布局如下图所示:

该程序的目的是在 SQL Server 中执行数据归档。如果我选择“创建表”,它将在我的数据库中生成新表(应该按顺序生成大约 40 个表),这些表的表结构(列、约束、触发器等)也与同一数据库中的原始表相似。这是如何工作的,我将在 c# 中执行 SQL 脚本并调用它们(所有 40 个脚本)来创建表。

现在,我添加了另一个按钮“传输数据”,它将在旧数据中选择特定数据(基于日期)并将它们传输到我创建的新表中。我将使用查询 Insert Into....SELECT from 来传输数据。

我的问题是我应该创建用于传输数据的 sql 脚本并在 c# 中执行它们还是只是将 SQL 查询放在我的 c# 代码中?

如果我使用 SQL 脚本,我应该将它们拆分为 40 个脚本还是将所有查询放在 1 个脚本中?我知道如果我将所有内容都放在一个脚本中,就好像发生错误一样,会很乏味,很难追踪问题的根源。

下面是 sql 查询的示例:

SET IDENTITY_INSERT Kiosk_Log_New ON
INSERT INTO Kiosk_Log_New(LOGID,
                          logAPPID,
                          logLOGTID,
                          logGUID,
                          logOriginator,
                          logReference,
                          logAssemblyName,
                          logFunctionName,
                          logMessage,
                          logException,
                          CreatedBy,
                          CreatedDate)
SELECT                  LOGID,
                          logAPPID,
                          logLOGTID,
                          logGUID,
                          logOriginator,
                          logReference,
                          logAssemblyName,
                          logFunctionName,
                          logMessage,
                          logException,
                          CreatedBy,
                          CreatedDate FROM Kiosk_Log
WHERE CreatedDate BETWEEN '2015-01-01' AND GETDATE()

编辑:由于许多建议的存储过程是最好的选择,这将是我的创建表脚本:

  string constr = ConfigurationManager.ConnectionStrings["constr"].ConnectionString;
        /*  open sql connection to execute SQL script: PromotionEvent_New   */
        try
        {
            using (SqlConnection con = new SqlConnection(constr))
            {
                con.Open();
                FileInfo file = new FileInfo("C:\\Users\\88106221\\Documents\\SQL Server Management Studio\\PromotionEvent_New.sql");
                string script = file.OpenText().ReadToEnd();
                Server server = new Server(new ServerConnection(con));
                server.ConnectionContext.ExecuteNonQuery(script);
                Display("PromotionEvent_New table has been created successfully");
                con.Close();



            }

        }
        catch(Exception ex)
        {

            textBox1.AppendText(string.Format("{0}", Environment.NewLine));
            textBox1.AppendText(string.Format("{0} MainPage_Load() exception - {1}{2}", _strThisAppName, ex.Message, Environment.NewLine));
            Display(ex.Message + "PromotionEvent_New could not be created");
            textBox1.AppendText(string.Format("{0}", Environment.NewLine));
            Debug.WriteLine(string.Format("{0} MainPage_Load() exception - {1}", _strThisAppName, ex.Message));


        }

【问题讨论】:

  • 这个问题解决了还是需要帮助?
  • 我需要帮助。请
  • 基本上,现在我必须创建一个按钮。单击该按钮时,它将读取一个 SQL 脚本。到目前为止,我已经完成了那部分。在脚本内部,它有大约 40 个行数查询。但这无论如何都不是问题。问题是我想点击按钮,然后它会执行那个sql脚本并在文本显示框中实时显示ROW COUNT(见我发布的线程快照)。
  • 所以文本框上的结果将是:表 A:200 行,表 B,342 行等。就像在 SQL Server 中运行计数查询时如何获取结果一样.但我不知道如何实现它。请指教。
  • 我还是卡住了

标签: c# sql-server ssms


【解决方案1】:

最好使用带有事务的存储过程来执行所有 INSERT 查询。

由于多种原因,不建议使用 John Ephraim Tugado 在上一篇文章中解释的 C# 代码提交查询;最重要的原因是,

  • 更轻松地维护 INSERT 查询
  • Web 服务器和数据库服务器之间的最小带宽消耗

从 C# 代码发送长查询字符串会占用 Web 服务器和数据库服务器之间的更多带宽,并且可能会在高流量情况下减慢数据库响应。

您可以对您的数据库执行以下 T-SQL 代码,为 transferring/archiving data 创建归档表的存储过程。此过程可确保您的所有 INSERTS 都在事务中执行,从而确保您最终不会遇到孤立表和不必要的麻烦。

传输数据的存储过程

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author: Lord Cookie
-- Create date: 11/01/2017
-- Description: Transfers data to existing archived tables
-- =============================================
CREATE PROCEDURE dbo.ArchiveData

AS
BEGIN

    SET NOCOUNT ON;
    BEGIN TRY
         --use transaction when inserting data else you may end up with orphaned data and hard to debug issues later on
        BEGIN TRANSACTION

        --add your INSERT queries one after the other below
        SET IDENTITY_INSERT Kiosk_Log_New ON
        INSERT INTO Kiosk_Log_New (LOGID,
        logAPPID,
        logLOGTID,
        logGUID,
        logOriginator,
        logReference,
        logAssemblyName,
        logFunctionName,
        logMessage,
        logException,
        CreatedBy,
        CreatedDate)
                SELECT
                    LOGID
                    ,logAPPID
                    ,logLOGTID
                    ,logGUID
                    ,logOriginator
                    ,logReference
                    ,logAssemblyName
                    ,logFunctionName
                    ,logMessage
                    ,logException
                    ,CreatedBy
                    ,CreatedDate
                FROM Kiosk_Log
                WHERE CreatedDate BETWEEN '2015-01-01' AND GETDATE()

        --add more of your insert queries below


        -- finally commit transaction
        COMMIT TRANSACTION
    END TRY
    BEGIN CATCH
        DECLARE @errorDetails NVARCHAR(MAX);
        set @errorDetails = 'Error ' + CONVERT(VARCHAR(50), ERROR_NUMBER()) +
        ', Severity ' + CONVERT(VARCHAR(5), ERROR_SEVERITY()) +
        ', State ' + CONVERT(VARCHAR(5), ERROR_STATE()) +
        ', Line ' + CONVERT(VARCHAR(5), ERROR_LINE());

          --roll back the transaction
        IF XACT_STATE() <> 0
        BEGIN
            ROLLBACK TRANSACTION
        END

        --you can log the above error message and/or re-throw the error so your C# code will see an error
        --but do this only after rolling back
    END CATCH;
END
GO

然后您可以使用 C# 调用上述存储过程,如下面的示例代码所示。

使用 C# 调用上述存储过程

using(SqlConnection sqlConn = new SqlConnection("Your database Connection String")) {
 using(SqlCommand cmd = new SqlCommand()) {
  cmd.CommandText = "dbo.ArchiveData";
  cmd.CommandType = CommandType.StoredProcedure;
  cmd.Connection = sqlConn;
  sqlConn.Open();
  cmd.ExecuteNonQuery();
 }
}

【讨论】:

  • 创建表呢?我也应该为他们创建存储过程吗?
  • 或者最好为每个表插入创建单独的存储过程或将它们全部转储到 1 个存储过程中?
  • 您必须确保在运行传输数据之前已经创建了表。表创建是一次性的工作,因此您可以确保一旦创建它们,然后只需担心传输数据。
  • 另外,您可以创建 40 个不同的存储过程,并从上述存储过程中调用它们中的每一个。那是另一种选择。这将使您的存储过程更小,这可能有助于维护它们。
  • 现在,我有用于在 40 个脚本文件中创建表的 sql 脚本。我应该把它们放在存储过程中吗?
【解决方案2】:

根据表的命名和设计,我建议创建一个脚本来为此创建一个存储过程,该过程将为您的每个表生成一个。我不是脚本专家,但它与为您的每个表或至少您在脚本中定义的表生成审计跟踪的脚本相同。

在您的 c# 应用程序中硬编码是一个很大的问题,因为有可能更改数据库。我们希望我们的应用能够灵活地以最少的工作量进行更改。

如果生成脚本来创建存储过程对您来说很困难,我仍然建议手动为此任务创建存储过程。

【讨论】:

  • 所以您的建议是在 sql 脚本中编写查询并在 c# 程序中调用它们?而不是在 c# 代码中编写 sql 查询?
  • 那么应该创建将数据从旧表传输到新表的脚本并在c#中按顺序执行吗?为什么要推荐存储过程?老实说,我不熟悉存储过程。
  • 没有。您在数据库本身内部创建存储过程。数据库管理员可以更轻松地根据需要更改脚本,而无需更改应用程序中的任何内容。有了这个,脚本将不依赖于开发人员并允许具有脚本知识的人来维护它。至于为什么推荐存储过程,我相信这里有足够的材料来解释这个主题。
  • 在数据库中创建存储过程后,您可以调用存储过程并在您的c#应用程序中传递必要的参数。
  • 我明白了。由于我已经完成了在程序中创建表的脚本调用,我应该将其更改为存储过程方法吗?
猜你喜欢
  • 2014-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多