У вас есть тип возврата SqlDataReader
, но вы ничего не возвращаете в своем коде. По крайней мере, вы должны объявить чтения данных и вернуть его так:
public SqlDataReader FetchAll(string tableName)
{
SqlDataReader reader;
using (SqlConnection conn = new SqlConnection(_ConnectionString))
{
string query = "SELECT * FROM " + tableName;
// added using block for your command (thanks for pointing that out Alex K.)
using (SqlCommand command = new SqlCommand(query, conn))
{
conn.Open(); // <-- moved this ABOVE the execute line.
reader = command.ExecuteReader(); // <-- using the reader declared above.
//conn.Close(); <-- not needed. using block handles this for you.
}
}
return reader;
}
Примечание, я заметил несколько других проблем, которые я видел, как хорошо, что вы можете увидеть мои комментарии.
Кроме того, я хочу отметить, что-то очень важное: вы всегда должны избегать конкатенации строк в запросах, так как это открывает вам до риска инъекции SQL атаки (как gmiley должным образом указал). В этом случае вы должны создать перечисление, которое содержит значения, связанные со всеми возможными именами таблиц, а затем использовать словарь для поиска имен таблиц на основе их значений перечисления. Если пользователь предоставляет недопустимое/неизвестное значение, вы должны были бы исключить аргумент.
Это еще не конец ваших проблем (как указывал По умолчанию). Вы не можете создать соединение в блоке using
, который будет располагаться и закрываться, как только он выйдет из блока, а затем использовать , который возвращается из метода. Если бы я был вами, я бы вернул DataSet
вместо SqlDataReader
. Вот как я это сделать:
Во-первых, создать перечисление возможных значений таблицы:
public enum Table
{
FirstTable,
SecondTable
}
и словарь, который отображает значения таблицы перечислений для имен таблиц (которые вы заселяют в вашем статическом конструкторе):
private static Dictionary<Table, string> _tableNames = new Dictionary<Table, string>(); // populate this in your static constructor.
А то вот ваш метод для извлечения данных:
public static System.Data.DataSet FetchAll(Table fromTable)
{
var ret = new System.Data.DataSet();
using (var conn = new System.Data.SqlClient.SqlConnection(_connectionString))
{
string tableName = "";
if (!_tableNames.TryGetValue(fromTable, out tableName)) throw new ArgumentException(string.Format(@"The table value ""{0}"" is not known.", fromTable.ToString()));
string query = string.Format("SELECT * FROM {0}", tableName);
using (var command = new System.Data.SqlClient.SqlCommand(query, conn))
{
using (var adapter = new System.Data.SqlClient.SqlDataAdapter(command))
{
adapter.Fill(ret);
}
}
}
return ret;
}
. Наконец, я бы посоветовал вам назвать переменные уровня класса с более низким верблюжьим корпусом для каждого соглашения, например. _connectionString
.
Вы никогда не возвращаете ничего, но вы объявили функцию для возврата 'SqlDataReader'. Кроме того, SQL-Injection возможно в 'string query =" SELECT * FROM "+ tableName;'. –
Если вы решили вернуть 'SqlDataReader', убедитесь, что он правильно закрыт и удален вызывающим абонентом, в противном случае легко запустить утечку SQL-соединений. –
Не бойтесь пытаться интерпретировать ошибку самостоятельно. Прочтите его и попытайтесь понять это буквально. Не все пути кода (т. Е. НЕ каждый путь выполнения) возвращают значения. Это можно удовлетворить/решить, если ВСЕ пути возвращают значение.Спросите себя, может ли хотя бы одно заявление о возвращении быть достигнуто все время. Начните с включения одного! –