我想使用 MySQL.Data 连接器查询我的 MySQL 数据库。我知道我可以使用实体框架或其他类似于 ORM 的便捷工具,例如 Dapper。但我想尝试“原生”方式。首先,我创建了一个处理查询执行的基础存储库
public abstract class BaseRepository
{
private async Task<MySqlConnection> GetDatabaseConnection()
{
string databaseConnectionString = "connection string";
MySqlConnection mySqlConnection = new MySqlConnection(databaseConnectionString);
await mySqlConnection.OpenAsync();
return mySqlConnection;
}
private async Task<DbDataReader> Execute(string commandText, Dictionary<string, object> parameterValues)
{
await using MySqlConnection mySqlConnection = await GetDatabaseConnection();
MySqlCommand mySqlCommand = new MySqlCommand()
{
CommandText = commandText,
Connection = mySqlConnection
};
foreach (KeyValuePair<string, object> parameterValue in parameterValues)
{
mySqlCommand.Parameters.AddWithValue(parameterValue.Key, parameterValue.Value);
}
await mySqlCommand.PrepareAsync();
return await mySqlCommand.ExecuteReaderAsync();
}
protected async Task<TResult> Read<TResult>(string commandText, Dictionary<string, object> parameterValues, Func<DbDataReader, Task<TResult>> action)
{
DbDataReader dbDataReader = await Execute(commandText, parameterValues);
return await action(dbDataReader);
}
protected async Task<int> Write(string commandText, Dictionary<string, object> parameterValues)
{
DbDataReader dbDataReader = await Execute(commandText, parameterValues);
return dbDataReader.RecordsAffected;
}
}
如您所见,有一个Read
andModify
方法。由于 MySQL 无法返回插入/更新的行(就像 Postgres 那样),我只返回受影响的行数以进行更新和删除。我知道基础存储库还不支持事务,但暂时忽略它。下面的例子演示了用法
public Task<User> GetUserAsync(string username)
{
return Read<User>(
"SELECT * FROM person WHERE username = @username",
new Dictionary<string, object>()
{
{ "username", username }
},
async dbDataReader =>
{
try
{
bool recordFound = await dbDataReader.ReadAsync();
if (!recordFound)
{
return null;
}
// ...
}
catch (Exception e)
{
throw;
}
});
}
问题是当调试器命中await dbDataReader.ReadAsync()
我得到这个异常
MySql.Data.MySqlClient.MySqlException (0x80004005):阅读器关闭时尝试读取无效。
为什么阅读器过早关闭?我该如何解决?
更新
正如评论中已经提到的,原因是await using MySqlConnection mySqlConnection = await GetDatabaseConnection();
在调用方法结束时关闭了连接。
我可以在每个存储库方法中处理整个阅读器逻辑,但我想避免在每个存储库方法中重复自己。
有没有办法可以重新设计BaseRepository
方法,以便它们不会过早关闭连接?