您可以将 ExecuteScalar 转换为泛型方法,从而允许您更改返回类型。
public T ExecuteScalar<T>(SqlCommand command)
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
command.Connection = connection;
//SqlDataAdapter da = new SqlDataAdapter(command); //not needed...
command.Connection.Open();
var result = command.ExecuteScalar();
//rather than just returning result with an implicit cast, use Max's trick from here: https://stackoverflow.com/a/2976427/361842
if (Convert.IsDbNull(result))
return default(T); //handle the scenario where the returned value is null, but the type is not nullable (or remove this to have such scenarios throw an exception)
if (result is T)
return (T)result;
else
(T)Convert.ChangeType(result, typeof(T));
}
}
不过,此方法与ExecuteNonQuery 函数中的逻辑不同,因此不能用相同的方法表示两者。
更新
关于您关于数据表的问题,我采用并改编了@JonSkeet's answer 以允许该类也处理数据表:
public class SqlDatabaseThing //: ISqlDatabaseThing
{
// ... additional code here ... //
public int ExecuteNonQuery(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteNonQuery(_connStr, command, sqlParameters);
public static int ExecuteNonQuery(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => cmd.ExecuteNonQuery());
public T ExecuteScalar(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteScalar(_connStr, command, sqlParameters);
public static T ExecuteScalar(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => ConvertSqlCommandResult(cmd.ExecuteScalar()));
public DataTable ExecuteToDataTable(SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteToDataTable(_connStr, command, sqlParameters);
public static DataTable ExecuteToDataTable(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters = new[]{}) =>
ExecuteCommand(connectionString, command, cmd => PopulateDataTable(cmd));
private static T ExecuteCommand<T>(string connectionString, SqlCommand command, IEnumerable<SqlParameter> sqlParameters, Func<SqlCommand, T> resultRetriever)
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
command.Parameters.AddRange(sqlParameters);
command.Connection = connection;
command.Connection.Open();
return resultRetriver(command);
}
}
private static DataTable PopulateDataTable(SqlCommand command)
{
var da = SqlDataAdapter(command);
var dt = new DataTable();
da.Fill(dt);
return dt;
}
private static T ConvertSqlCommandResult(object result)
{
if (Convert.IsDbNull(result))
return default(T);
if (result is T)
return result as T;
(T)Convert.ChangeType(result, typeof(T));
}
}
注意:在您的代码中,您包含了与获取特定任务相关的逻辑。这应该与您的通用数据库逻辑分开(即假设您希望为各种查询返回数据表,并且不想每次都重写您的GetDT 代码)。因此,我在下面提供了额外的示例代码,展示了如何将该逻辑分离到另一个类中......
public class TaskRepository //: IRepository<Task>
{
ISqlDatabaseThing db;
public TaskRepository(ISqlDatabaseThing db)
{
this.db = db;
}
readonly string GetByIdCommand = "select id, userid, name from tasks where id = @id";
readonly string GetByIdCommandParameterId = "@id"
readonly SqlDbType GetByIdCommandParameterIdType = SqlDbType.BigInt;
public Task GetById(long id)
{
var command = new SqlCommand(GetByIdCommand);
var parameters = IEnumerableHelper.ToEnumerable<SqlParameter>(new SqlParameter(GetByIdCommandIdParameter, GetByIdCommandIdParameterType, id));
var dataTable = db.ExecuteToDataTable(command, parameters);
return DataTableToTask(dataTable)[0];
}
private IEnumerable<Task> DataTableToTask(DataTable dt)
{
foreach (var row in dt.Rows)
{
yield return DataRowToTask(row);
}
}
private Task DataRowToTask (DataRow dr)
{
return new Task()
{
Id = dr["Id"]
,Name = dr["Name"]
,UserId = dr["UserId"]
};
}
}
public static class IEnumerableHelper
{
public static IEnumerable<T> ToEnumerable<T>(params T[] parameters)
{
return parameters;
}
}
注意:此代码未经测试;有任何问题请告诉我。