增强我的代码的指南

时间:2009-09-04 02:53:06

标签: c# sql-server progressive-enhancement

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

  1. 喜欢插入代码来验证记录是否为空,如果在复制文件时出现问题,或者如果是EOF,我该怎么办?
  2. 这段代码在form_load()中运行并在win form应用程序中运行,如果我运行程序exe,我不会出现什么形式?我想让这个程序像在Windows后面运行一样。只会出现错误或成功的消息框?
  3. 任何有关解决方案,指导或参考的帮助都非常感谢。
  4. 提前谢谢!

    
    //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); }

5 个答案:

答案 0 :(得分:5)

一些建议:

  • 将其移出表单。业务逻辑和数据访问不属于表单(View)。将其移至单独的班级。
  • 将MessageBox代码保留在表单中。这是显示逻辑。整个try..catch可以移出方法;只是让方法抛出异常。并且不要捕获System.Exception - 捕获您期望的数据库。
  • 我回应Ty对IDisposable和使用陈述的评论。
  • 阅读Extract MethodSingle Responsibility Principle。这个方法做了很多,而且很长。分手吧。
  • 移出一些字符串硬编码。如果连接字符串或文件路径发生变化怎么办?为什么不将它们放在配置文件中(或者至少使用一些常量)?

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

答案 1 :(得分:4)

这肯定是一些代码,如果你愿意,我肯定可以推荐很多改进它的东西。

我要做的第一件事就是阅读IDisposable然后我会重新编写DataReader,如下所示。

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("---------------------------------");
   }
}

然后在捕获之后,将以下内容移除并关闭。

finally
{
   sqlConnection1.Dispose(); //close con
}

答案 2 :(得分:2)

除了已经提供的其他一些答案之外,您可能还需要考虑使用交易来保护数据操作。

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

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

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

答案 3 :(得分: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;
    }
}

答案 4 :(得分:0)

  1. 使用SELECT查询查找非空行(您似乎与EOF问题相处)。
  2. form_load事件中,通过程序参数使表单不可见。
  3. 为什么不使用INSERT INTO(然后删除)?