2014-09-04 358 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