SqlDataAdapter.SelectCommand не возвращает правильный результат

Я просто столкнулся с проблемой с моим кодом.

Я хочу выбрать некоторые данные из базы данных, используя свойство SqlDataAdapter SelectCommand.

Мой код выглядит так:

static SqlConnection sqlConnection;
static SqlDataAdapter daDBData = new SqlDataAdapter();
static SqlCommand command = new SqlCommand();
static DataSet dsDBData = new DataSet("DBData");
static DataTable tblDBData;
static DataRow drCurrent;

public static DataTable dbDataGet(string tabname, string where)
{
    sqlConnection = dbConnect();    //sqlConnection setup working fine, defined in another method
    string helper = "SELECT * FROM " + tabname + where; 
    command = new SqlCommand(helper, sqlConnection);
    daDBData.SelectCommand = command;

    daDBData.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    daDBData.Fill(dsDBData, tabname);

    tblDBData = dsDBData.Tables[tabname];
    return tblDBData;
}

Моя проблема в том, что в tblDBData будут возвращены все существующие строки моей таблицы базы данных. Что мне здесь не хватает?


person Mátyás Németh    schedule 18.02.2020    source источник
comment
Что передается в качестве значения параметра where? Может быть, если он пуст, вы просто выбираете ВСЕ данные из своей таблицы?   -  person Just Rudy    schedule 18.02.2020
comment
Можете ли вы сбросить сюда все значение helper?   -  person JonE    schedule 18.02.2020
comment
Попробуйте добавить пробелы: SELECT * FROM + + tabname + + where; Содержит ли слово WHERE: SELECT * FROM + + tabname + WHERE + where;   -  person jdweng    schedule 18.02.2020
comment
Помимо проблемы, о которой вы спрашиваете, меня глубоко беспокоит статический характер этого кода. Это абсолютно не потокобезопасно. Если вы используете это, например, в веб-приложении, соединения будут пропущены и оставлены неиспользованными. Включение MARS предотвратит прямые ошибки об открытых программах чтения в соединении, но вы можете легко перегрузить соединение слишком большим количеством наборов результатов. Лучше всего просто использовать ADO.NET. Такие занятия - плохая идея.   -  person madreflection    schedule 18.02.2020
comment
Содержимое вспомогательной строки @JonE: SELECT * FROM products WHERE DATEDIFF(day, sale_date, GetDate()) ›= 365 AND available=1   -  person Mátyás Németh    schedule 18.02.2020


Ответы (1)


Что касается блоков кода, вероятно, будет справедливо сказать, что над ними нужно много работать. Почти в каждой строке есть что-то, что можно было бы улучшить, но вся концепция, которую она воплощает, вызывает возражения, потому что она по своей сути представляет огромный риск для безопасности. Вот немного улучшенная версия:

//Don't need any of those static variables. Stop making everything static..
//In a properly structured C# program almost NOTHING should be declared as static

        //Method names in C# use PascalCase convention, not camelCase
        public DataTable DbDataGet(string tableName, string whereClause)
        {

            //this could be a massive security risk if there is any way at all that the 
            //user can influence the contents of the whereClause. DON'T DO IT if they can
            SqlDataAdapter da = new SqlDataAdapter(
              $"SELECT * FROM {tableName} WHERE {whereClause}",
              GetConnectionString() //in this simplistic context, get a string, not a SqlConnection, then you don't handle disposal
            );

            DataTable dt = new DataTable();

            da.Fill(dt);

            return dt;
        }

Ага; весь этот код, который вы написали, сводится всего к 4 строкам. Это по-прежнему серьезная проблема, когда вы просто перебрасываете строку с предложением where. Единственный способ избежать этого с помощью этого подхода - начать разбивать строку where на набор классов предикатов, инъекцию sql, защищенную на уровне столбца и оператора, и добавлять значения в SqlParameterCollection - это по сути прокатка ваших собственных данных доступ к библиотеке и не стоит заморачиваться, учитывая, что многие десятки людей уже сделали это (включая Microsoft)

Вместо этого подумайте о том, чтобы уйти от этой ужасной кроличьей норы, вообще НЕ выполняя доступ к данным таким образом. Выбросьте все это в корзину и вместо этого используйте Dapper. Это не очень большая кривая обучения с того места, где вы сейчас находитесь, и все будет делаться более безопасным, надежным и простым в использовании способом.


В качестве примечания к предложению WHERE вы говорите в комментариях, которые вы используете:

WHERE DATEDIFF(day, sale_date, GetDate()) >= 365 AND available=1

Не делай и этого. Здесь вы выполняете функциональную операцию над вводом данных в таблицу. Если в вашей таблице миллион дат, эту функцию нужно будет вызывать миллион раз. Он чертовски медленный, использует огромное количество ресурсов и калечит использование индексов. И это совершенно не нужно. Вы ищете все товары, проданные более года назад? Вычислите ОДНУ ДАТУ того числа, которое было год назад, и используйте SALE_DATE из сказки без каких-либо изменений по сравнению с ней:

-- in your sql
WHERE sale_date < @someDate and available = 1

//in your c#
mySqlCommand.Parameters.AddWithValue("@someDate", DateTime.UtcNow.AddYears(-1));

Увидеть разницу? Здесь С# вычисляет дату один раз и предоставляет ее в качестве параметра постоянного значения для запроса. В таблице из миллиона дат выполняется только одно простое сравнение. Мы не подсчитываем, сколько дней назад было миллион разных дат, а затем выбираем только те различия > 365.

person Caius Jard    schedule 19.02.2020