C# 如何正确存储it数据库中的对象列表?

C# 如何正确存储it数据库中的对象列表?,c#,.net,stored-procedures,ado.net,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 { g

我从事的项目是大约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; }
}
正如您在foreach方法的SaveReport函数中所看到的,我打开连接,将项传递给存储过程,然后关闭连接

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


我是否应该改变将收藏存储到数据库的态度?如果是,我应该怎么做

您应该在创建SqlConnection时添加一个using语句,并在进入循环之前打开它。当您退出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;
    }
}
public void保存报告(IEnumerable报告)
{
尝试
{
使用(SqlConnection conn=newsqlconnection(“connetcion字符串”))
{
conn.Open();
使用(SqlTransaction tr=conn.BeginTransaction())
使用(SqlCommand cmd=newsqlcommand(“SaveEcxelReport”,conn,tr))
{
cmd.CommandType=CommandType.storedProcess;
cmd.Parameters.Add(“@siteNum”,SqlDbType.Int);
cmd.Parameters.Add(“@dateReport”,SqlDbType.DateTime);
……其他参数。。。。
foreach(报告中的var记录)
{
cmd.Parameters[“@siteNum”].Value=record.siteNum;
cmd.Parameters[“@dateReport”].Value=record.dateReport;
…设置其他参数的值
cmd.ExecuteNonQuery();
}
tr.Commit();
}
}
}
抓住
{
//如果出现问题,将自动执行回滚
//当您退出上面的using块时
//如果(tr!=null)
//{
//tr.RollBack();
//}
// ------
//在这里,您应该在抛出之前记录错误。
//记录错误是一个好习惯,通常也是救命稻草
// ------
//但是如果你不记录或者你不做任何其他事情
//但是只要把球扔出去,那么整个试球就没用了
//你可以完全移除它
投掷;
}
}

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

,因为SqlTransaction也实现了IDisposable-值得将其包装在using block中。是的,我知道,但是如何在catch block中回滚?我们可以添加对tr.Dispose()的直接调用;当需要时(或者最后使用tr.Dispose),实际上不需要在catch块中显式回滚(当然可以)。调用dispose时-如果尚未提交,则事务将回滚。因此,您可以使用(var tr=conn.BeginTransaction()){…tr.Commit();}来执行
,很抱歉,这是一个非常复杂的问题,但是您确定吗,因为我还没有找到这方面的证据。你有什么实际的联系来解释这种行为吗?我已经做了很多年了,只是通过实验再次验证了这一点,但我不确定是否有任何联系证实了这一点。DbTransaction.Dispose的文档说明“Dispose应该回滚事务。但是,Dispose的行为是特定于提供程序的”。虽然不确定除了在未提交时回滚之外,处理事务还能做些什么,但似乎没有其他明智的选择
TransactionScope
也会这样做(尽管这次是“正式的”)。
      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
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;
    }
}