在我的整个程序中,我将重复使用(MySQL 的)SELECT 命令。每次,我都必须建立连接和东西。我正在考虑制作一个接收 SELECT 命令字符串并返回参数的等效 DataReader 的方法。我认为这将帮助我减少每次必须生成的大量代码。
我想以这样的方式使用它:
MySqlDataReader myReader = myObj.loadDataToReader("SELECT * FROM tblSample");
然后,我可以像操作常规 MySqlDataReader 一样操作 myReader
。但是,我担心在使用数据读取器时必须打开连接这一事实,当然,需要关闭它(读取器和连接)和所有(我相信这是一种传统的安全措施) ).我一直在网上查看相关内容,但似乎找不到有关如何执行此操作的提示。
我正在尝试,我有以下代码行:
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 */ }
但是,我收到一条消息说“阅读器关闭时读取尝试无效!” 我怎样才能纠正这个问题并让它发挥作用?或者更确切地说,是否有更合适的方法来做到这一点?我如何确保我的连接/阅读器在使用后关闭?
最佳答案
您可以使您的方法通用并注入(inject)一个函数以在读取器上工作,然后返回函数的输出而不是读取器:
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
实现了IDisposable
,所以我为reader添加了using语句- 我使用 ADO.NET 接口(interface)方法而不是构造函数来创建命令
- 我删除了 catch block ,因为当您离开 using block 时连接会自动关闭,并且 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 Catalog
或 Database
在连接字符串中设置数据库,这比在 select 语句前面加上 USE 更可取数据库
子句。
关于C# 和 MySQL - 返回 DataReader(或其内容)的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25671725/