C# 如何正确存储it数据库中的对象列表?
我从事的项目是大约8年前创建的,它使用ADO.NET技术 我要保存在表中的数据是对象列表: 以下是自定义类: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
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;
}
}