1

该程序会将表 1 中的所有记录复制到表 2 中,并写入文本文件。完成复制所有记录后,将删除记录,使 table1 为空,然后再添加新记录。我喜欢增强我的代码,例如:

  1. 比如插入代码来验证记录是否为空,如果在复制文件时遇到问题,或者如果它是 EOF,我该怎么办?
  2. 此代码在 form_load() 中并在 win 表单应用程序中运行,如果我运行程序 exe,我不显示要出现的表单怎么办?我想让这个程序就像在后面的 Windows 上运行一样。只有错误或成功的消息框会出现?
  3. 在解决方案,指导或参考方面的任何帮助都非常感谢。

先感谢您!


//create connection
 SqlConnection sqlConnection1 =
   new SqlConnection("Data Source=.\SQLEXPRESS;Database=F:\Test2.mdf;Integrated Security=True;User Instance=True");
//command insert into queries
  SqlCommand cmdCopy = new SqlCommand();
  cmdCopy.CommandType = System.Data.CommandType.Text;
  cmdCopy.CommandText = "INSERT INTO tblSend (ip, msg, date) SELECT ip, msg, date FROM tblOutbox";
  cmdCopy.Connection = sqlConnection1;
//insert into text file
  SqlCommand cmd = new SqlCommand();
  cmd.CommandType = CommandType.Text;
  cmd.CommandText = "SELECT * FROM tblOutbox";
  cmd.Connection = sqlConnection1;
  sqlConnection1.Open();
  StreamWriter tw = File.AppendText("c:\INMS.txt");
  SqlDataReader reader = cmd.ExecuteReader();
  tw.WriteLine("id, ip address, message, datetime");
  while (reader.Read())
  {
   tw.Write(reader["id"].ToString());
   tw.Write(", " + reader["ip"].ToString());
   tw.Write(", " + reader["msg"].ToString());
   tw.WriteLine(", " + reader["date"].ToString());
  }
  tw.WriteLine("Report Generate at : " + DateTime.Now);
  tw.WriteLine("---------------------------------");
  tw.Close();
  reader.Close();
//command delete
  String strDel = "DELETE tblOutbox";
  SqlCommand cmdDel = new SqlCommand(strDel, sqlConnection1);
//sqlConnection1.Open(); //open con
cmdCopy.ExecuteScalar(); cmd.ExecuteNonQuery(); //execute insert query cmdDel.ExecuteScalar();//execute delete query
sqlConnection1.Close(); //close con //*****************************************************
} catch (System.Exception excep) { MessageBox.Show(excep.Message); }

4

5 回答 5

5

几点建议:

  • 将其移出表格。业务逻辑和数据访问不属于表单(View)。将其移至单独的类。
  • 将 MessageBox 代码保留在表单中。这就是显示逻辑。整个 try..catch 可以移出方法;只是让方法抛出异常。并且不要捕获 System.Exception - 捕获您期望的数据库。
  • 我赞同 Ty 对 IDisposable 和 using 语句的评论。
  • 阅读提取方法单一职责原则。这个方法做的很多,而且很长。分开来。
  • 将一些字符串硬编码移出。如果您的连接字符串或文件路径发生变化怎么办?为什么不将它们放在配置文件中(或至少使用一些常量)?

无论如何,对于初学者来说。:)

于 2009-09-04T03:37:42.037 回答
4

That sure is some code and I sure could recommend a lot of things to improve it if you care.

First thing I would do is read up on IDisposable then I would re-write that DataReader as following.

using(StreamWriter tw = File.AppendText("c:\INMS.txt"))
{
    using(SqlDataReader reader = cmd.ExecuteReader())
    {
      tw.WriteLine("id, ip_add, message, datetime");
      while (reader.Read())
      {
         tw.Write(reader["id"].ToString());
         tw.Write(", " + reader["ip_add"].ToString());
         tw.Write(", " + reader["message"].ToString());
         tw.WriteLine(", " + reader["datetime"].ToString());
      }
      tw.WriteLine(DateTime.Now);
      tw.WriteLine("---------------------------------");
   }
}

Then after your catch, put the following and remove the close call.

finally
{
   sqlConnection1.Dispose(); //close con
}
于 2009-09-04T03:27:07.430 回答
2

除了已经给出的其他一些答案之外,您可能还需要考虑使用Transaction保护数据操作。

我假设您不希望以下任何操作部分完成:

  cmdCopy.ExecuteScalar();
  cmd.ExecuteNonQuery(); //execute insert query
  cmdDel.ExecuteScalar();//execute delete query

如果您正在处理许多行,您可能希望批量更新,但这是一个完全不同的问题。

于 2009-09-04T04:12:28.110 回答
2

首先感谢您尝试提高您的技能并愿意像这样发布您的代码。我相信这是成为一个更好的程序员的第一步,就是拥有这种态度。

这是一个回答您的一些问题的实现。我已经将一些旧代码提取到方法中,并将一些职责转移到它们自己的类中。

免责声明:

  • 尽管代码可以编译,但我并没有针对数据库运行它,因此我可能遗漏了一些小事情。
  • 我不得不在不知道确切要求的情况下停止某些重构,并且仍然尝试保持一些概念简单。

.

using System;
using System.Configuration;
using System.Data.SqlClient;
using System.IO;

// Program.cs
static class Program
{
    [STAThread]
    static void Main()
    {
        try
        {
            MailArchiver.Run();
            Console.WriteLine("Application completed successfully");
        }
        catch (Exception ex)
        {
            Console.WriteLine("Unexpected error occurred:");
            Console.WriteLine(ex.ToString());
        }

    }
}

// Reads new messages from DB, save it to a report file 
// and then clears the table
public static class MailArchiver
{

    public static void Run()
    {
        // Might be a good idea to a datetime suffix 
        ReportWriter.WriteFile(@"c:\INMS.txt");
        CopyAndClearMessages();
    }

    private static void CopyAndClearMessages()
    {
        SqlConnection cn = DbConnectionFactory.CreateConnection();
        cn.Open();

        try
        {
            SqlTransaction tx = cn.BeginTransaction();

            try
            {
                CopyMessages(cn, tx);
                DeleteMessages(cn, tx);
                tx.Commit();
            }
            catch
            {
                tx.Rollback();
                throw;
            }
        }
        finally
        {
            cn.Close();
        }
    }

    private static void DeleteMessages(SqlConnection cn, SqlTransaction tx)
    {
        var sql = "DELETE FROM tblOutbox";
        var cmd = new SqlCommand(sql, cn, tx);
        cmd.CommandTimeout = 60 * 2;  // timeout 2 minutes 
        cmd.ExecuteNonQuery();
    }

    private static void CopyMessages(SqlConnection cn, SqlTransaction tx)
    {
        var sql = "INSERT INTO tblSend (ip, msg, date) SELECT ip, msg, date FROM tblOutbox";
        var cmd = new SqlCommand(sql, cn, tx);
        cmd.CommandTimeout = 60 * 2;  // timeout 2 minutes 
        cmd.ExecuteNonQuery();
    }
}

// Provides database connections to the rest of the app.
public static class DbConnectionFactory
{
    public static SqlConnection CreateConnection()
    {
        // Retrieve connection string from app.config
        string connectionString = ConfigurationManager.ConnectionStrings["MailDatabase"].ConnectionString;
        var cn = new SqlConnection(connectionString);

        return cn;
    }
}

// Writes all the data in tblOutbox to a CSV file
public static class ReportWriter
{
    private static SqlDataReader GetData()
    {
        SqlConnection cn = DbConnectionFactory.CreateConnection();
        cn.Open();

        try
        {
            var cmd = new SqlCommand();
            cmd.CommandText = "SELECT * FROM tblOutbox";
            cmd.Connection = cn;

            return cmd.ExecuteReader();
        }
        finally
        {
            cn.Close();
        }
    }

    public static void WriteFile(string filename)
    {
        if (File.Exists(filename))
        {
            // This might be serious, we may overwrite data from the previous run.
            // 1. You might want to throw your own custom exception here, should want to handle this
            //    condition higher up.
            // 2. The logic added here is not the best and added for demonstration purposes only.
            throw new Exception(String.Format("The file [{0}] already exists, move the file and try again"));
        }
        var tw = new StreamWriter(filename);

        try
        {
            // Adds header record that describes the file contents
            tw.WriteLine("id,ip address,message,datetime");

            using (SqlDataReader reader = GetData())
            {
                while (reader.Read())
                {
                    var id = reader["id"].ToString();
                    var ip = reader["ip"].ToString();

                    //msg might contain commas, surround value with double quotes
                    var msg = reader["msg"].ToString();
                    var date = reader["data"].ToString();

                    if (IfValidRecord(id, ip, msg, msg, date))
                    {
                        tw.WriteLine(string.Format("{0},{1},{2},{3}", id, ip, msg, date));
                    }
                }

                tw.WriteLine("Report generated at : " + DateTime.Now);
                tw.WriteLine("--------------------------------------");
            }

        }
        finally
        {
            tw.Close();
        }

    }

    private static bool IfValidRecord(string id, string ip, string msg, string msg_4, string date)
    {
        // this answers your question on how to handle validation per record.
        // Add required logic here
        return true;
    }
}
于 2009-09-05T06:38:23.020 回答
0
  1. 使用 SELECT 查询来查找非空行(您似乎与 EOF 问题相处融洽)。
  2. form_load事件中,程序参数使表单不可见。
  3. 为什么不使用INSERT INTO(然后 DELETE)?
于 2009-09-04T03:12:50.320 回答