2014-09-04 29 views
1

在我的程序中,我将重复使用SELECT命令(MySQL的)。每一次,我都必须建立连接和东西。我正在考虑制作一个方法,它接收一个SELECT命令字符串并返回该参数的等效DataReader。我认为这会帮助我减少每次产生的大量代码。C#和MySQL - 返回DataReader(或其内容)的方法

我想以这样的方式来使用它的是:

MySqlDataReader myReader = myObj.loadDataToReader("SELECT * FROM tblSample"); 

然后,我可以操纵myReader像一个普通的了MySqlDataReader。然而,我担心在使用数据读取器时连接必须打开,当然,需要关闭连接(阅读器和连接)以及所有(传统的安全措施,我相信)。我一直在看互联网上的东西,我似乎无法找到如何做到这一点的暗示。

我想,我有下面的代码行:

public MySqlDataReader loadDataToReader(string selectCommand) 
{ 
    MySqlDataReader myReader = null; 
    string myConnectionString = "Data Source = " + server + "; User = " + user + "; Port = 3306; Password = " + password + ";"; 
    string useDataBaseCommand = "USE " + dbName + ";"; 
    using (MySqlConnection myConnection = new MySqlConnection(myConnectionString)) 
    { 
     using (MySqlCommand myCommand = new MySqlCommand(useDataBaseCommand + selectCommand, myConnection)) 
     { 
      try 
      { 
       myConnection.Open(); 
       myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection); 
      } 
      catch (Exception ex) 
      { 
       myConnection.Close(); 
       MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); 
      } 
      return myReader; 
     } 
    } 
} 

而在另一个类的方法,我创建了一个对象,以便能够使用上面定义的方法,在这样一种方式,它看起来像这样:

string selectTableCommand = "SELECT * FROM tblusers WHERE Username = \'" + txtID.Text + "\' AND Password = \'" + txtPassword.Text + "\';"; 
MySQLOperations objSQLOperations = new MySQLOperations("localhost", "root", "mypass", "mydatabase"); 
MySqlDataReader myDataReader = objSQLOperations.loadDataToReader(selectTableCommand); 
if (myDataReader.Read() && txtPassword.Text.Equals(myDataReader["Password"].ToString())) 
    { /* do something */ } 
else 
    { /* do something */ } 

但是,我收到一条消息,提示“读取器关闭时无效尝试读取!” 我该如何纠正这种情况并使之发挥作用?或者说,是否有更合适的方法来做到这一点?我怎样才能确保我的连接/阅读器在使用后关闭?

+0

改为使用DataTable。将读取器载入数据表,即'var dt = new DataTable(); dt.Load(myReader);'然后将DataTable返回给调用者做它的东西。 – adaam 2014-09-04 17:43:13

+0

'DataSet'或'DataTable'通常是比'DataReader'更好的选择。你也应该参数化你的SQL语句,而不是连接它们:http://en.wikipedia.org/wiki/SQL_injection – 2014-09-04 17:43:29

+0

谢谢你的想法。我将使用DataTable来代替。 – Jill 2014-09-04 18:29:22

回答

3

你可以让你的方法一般和注入的函数,在读者的工作,然后返回函数的输出,而不是读者:

public T LoadDataToReader<T>(string selectCommand, Func<IDataReader,T> ProcessResults) 
{ 
    string myConnectionString = "Data Source = " + server + "; User = " + user + "; Port = 3306; Password = " + password + ";"; 
    string useDataBaseCommand = "USE " + dbName + ";"; 
    using (var myConnection = new MySqlConnection(myConnectionString)) 
    { 
     myConnection.Open(); 

     using (var myCommand = myConnection.CreateCommand()) 
     { 
      myCommand.CommandText = useDataBaseCommand + selectCommand; 

      using(var myReader = myCommand.ExecuteReader(CommandBehavior.CloseConnection)) 
      { 
       return ProcessResults(myReader); 
      } 
     } 
    } 
} 

我也做了一些其他的变化:

  • IDataReader implements IDisposable,所以我为读者添加了使用语句
  • 我使用ADO.NET接口方法创建命令而不是构造函数
  • 我删除了catch块,因为当您离开using块时连接关闭自动发生,并且UI代码(例如,MessageBox)不属于DAL代码。这应该作为围绕调用此方法的try/catch来完成。
  • 我大写功能的第一个字母,使其与.NET编码标准相一致

然后,你只需按如下方式使用它:

public static string GetStringData(IDataReader reader) 
{ 
    var ord_name = reader.GetOrdinal("Name"); 

    if(reader.Read()) 
    return reader.GetString(ord_name); 

    return null; 
} 

public static IEnumerable<Foo> GetFoos(IDataReader reader) 
{ 
    var ord_name = reader.GetOrdinal("Name"); 
    var foos = new List<Foo>(); 

    while(reader.Read()) 
    foos.Add(new Foo {Name = reader.GetString(ord_name)}); 

    return foos; 
} 

static void Main(string[] args) 
{ 
    var program = new Program(); 
    try 
    { 
     var name = program.LoadDataToReader("SELECT name FROM thename", GetStringData); 
    } 
    catch(Exception ex) 
    { 
     MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); 
    } 
    try 
    { 
     var foos = program.LoadDataToReader("SELECT foos FROM footable", GetFoos); 
    } 
    catch(Exception ex) 
    { 
     MessageBox.Show(ex.Message, "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error); 
    } 
} 

此外,你应该通过连接字符串,而不是从字段中构建。或者,您可以为整个连接字符串设置一个字段(仅构建一次而不是每次执行)并使用该字段。

另外,数据库可以在连接字符串中设置为Initial CatalogDatabase,这比将select语句加上USE database子句前缀更好。

+0

我决定要坚持上面所做的,只是要将其改为DataTable。不过,先生,谢谢你。我可能会在某一天以某种方式使用它。 – Jill 2014-09-04 18:33:25

+0

@Jill请记住'DataSet'和'DataTable'都是'IDisposable'。由于数据适配器必须执行额外的步骤来确定结果集模式,因此它们都是内存明智和查询明智的重对象。如果提前知道该模式,数据读取器可以更好地使用,但使用像实体框架或nHibernate这样的ORM将比任何建议的选项更好。 – 2014-09-04 23:06:32