如何正确存储数据库对象列表?

时间:2017-12-26 16:53:55

标签: c# .net stored-procedures ado.net

我从事大约8年前创建的项目,它使用ADO.NET技术。

我要在表格中保存的数据是对象列表:

这是自定义类:

public class ReportTrafficDepartment
{
    public int id { get; set; }
    public System.Nullable<int> siteNum { get; set; }
    public System.Nullable<System.DateTime> dateReport { get; set; }
    public string siteName { get; set; }
    public System.Nullable<int> prog1 { get; set; }
    public System.Nullable<int> progLayout1 { get; set; }
    public System.Nullable<int> prog2 { get; set; }
    public System.Nullable<int> progLayout2 { get; set; }
    public System.Nullable<bool> isLOZ { get; set; }
    public System.Nullable<System.DateTime> start { get; set; }
    public System.Nullable<System.DateTime> end { get; set; }
    public System.Nullable<System.TimeSpan> time { get; set; }
    public System.Nullable<float> Prog1ToProg2Check { get; set; }
    public string comment { get; set; }
}

以下是我想保存数据时调用的函数:

    public void saveReport(IEnumerable<ReportTrafficDepartment> report)
    {
        try
        {

            SqlConnection conn = new SqlConnection("connetcion string");

            foreach (var record in report)
            {
                SqlCommand cmd = new SqlCommand("SaveEcxelReport", conn);
                cmd.CommandType = CommandType.StoredProcedure;

                cmd.Parameters.Add("@siteNum", SqlDbType.Int).Value = record.siteNum;
                cmd.Parameters.Add("@dateReport", SqlDbType.DateTime).Value = record.dateReport;
                cmd.Parameters.Add("@siteName", SqlDbType.NVarChar).Value = record.siteName;
                cmd.Parameters.Add("@prog1", SqlDbType.Int).Value = record.prog1;
                cmd.Parameters.Add("@progLayout1", SqlDbType.Int).Value = record.progLayout1;
                cmd.Parameters.Add("@prog2", SqlDbType.NVarChar).Value = record.prog2;
                cmd.Parameters.Add("@progLayout2", SqlDbType.Int).Value = record.progLayout2;
                cmd.Parameters.Add("@isLOZ", SqlDbType.Bit).Value = record.isLOZ;
                cmd.Parameters.Add("@start", SqlDbType.DateTime).Value = record.start;
                cmd.Parameters.Add("@end", SqlDbType.DateTime).Value = record.end;
                cmd.Parameters.Add("@Prog1ToProg2Check", SqlDbType.Real).Value = record.Prog1ToProg2Check;
                cmd.Parameters.Add("@comment", SqlDbType.NVarChar).Value = record.comment;

                conn.Open();
                cmd.ExecuteNonQuery();
                conn.Close();
            }
        }
        catch
        {
            throw;
        }
    }

这里是我用来向表中插入记录的存储过程:

      ALTER PROCEDURE [dbo].[SaveEcxelReport]
         @siteNum INT = NULL,
         @dateReport DATETIME = NULL,
         @siteName NVARCHAR(255) = NULL,
         @prog1 INT = NULL,
         @progLayout1 INT = NULL,
         @prog2 INT = NULL,
         @progLayout2 INT = NULL,
         @isLOZ BIT = NULL,
         @start DATETIME = NULL,
         @end DATETIME = NULL,
         @time DATETIME = NULL,
         @Prog1ToProg2Check REAL = NULL,
         @comment NVARCHAR(255) = NULL

        AS   
        BEGIN
          SET NOCOUNT ON;
          insert into dbo.ReportTrafficDepartment(siteNum, dateReport, siteName, prog1, progLayout1, prog2, progLayout2, isLOZ, [start], [end], [time], Prog1ToProg2Check, comment) 
                 values (@siteNum, @dateReport, @siteName, @prog1,@progLayout1, @prog2, @progLayout2, @isLOZ, @start, @end, @time, @Prog1ToProg2Check, @comment) 
        END

正如你在foreach方法中的SaveReport函数中看到的那样,我打开连接我将项目传递给存储过程然后我关闭连接。

但是,我认为我的态度是错误的(即在foreach循环中打开和关闭连接并不是一个好主意)。

如果是的话,我应该如何改变存储集合的态度到数据库?

1 个答案:

答案 0 :(得分:2)

您应该在创建SqlConnection时添加using语句,并在进入循环之前将其打开。当您从使用块退出时,using语句将自动关闭连接。 另一个小步骤是在循环外创建一次参数并在循环内设置值。无需在每个循环中创建所有参数集,您可以重复使用它们。 但最重要的解决方法是在代码周围添加一个事务,以防止在异常的情况下部分插入可枚举。

public void saveReport(IEnumerable<ReportTrafficDepartment> report)
{
    try
    {

        using(SqlConnection conn = new SqlConnection("connetcion string"))
        {
            conn.Open();
            using(SqlTransaction tr = conn.BeginTransaction())
            using(SqlCommand cmd = new SqlCommand("SaveEcxelReport", conn, tr))
            {
                 cmd.CommandType = CommandType.StoredProcedure; 
                 cmd.Parameters.Add("@siteNum", SqlDbType.Int);
                 cmd.Parameters.Add("@dateReport", SqlDbType.DateTime);
                 .... other parameters ....
                foreach (var record in report)
                {
                    cmd.Parameters["@siteNum"].Value = record.siteNum;
                    cmd.Parameters["@dateReport"].Value = record.dateReport;

                    ... set the values for other parameters

                    cmd.ExecuteNonQuery();
               }
               tr.Commit();
            }
        }
    }
    catch
    {
        // If something goes wrong the rollback is executed automatically 
        // when you exit from the using block above
        //if(tr != null) 
        //{
        //   tr.RollBack();
        //}

        // ------
        // Here you should log the error before throwing. 
        // It is a good habit and often a lifesaver to log the errors 
        // ------

        // But if you don't log or you don't do anything else 
        // but just throw then the whole try catch is useless 
        // and you can completely remove it 
        throw;
    }
}

在完成这些简单修复之后,您应该看一下使用ORM,它可以只获取可枚举的数据并将其存储到数据库中而无需进一步编码