динамически создавать оператор SQL на основе критериев выбора флажков - PullRequest
0 голосов
/ 07 августа 2011

У меня есть страница .aspx, в которой продукты сгруппированы по различным категориям в базе данных SQL Server 2005.

Пользователь должен иметь возможность выбирать любую комбинацию.Например, выбор «Бежевый» и «Черный» из категории «ЦВЕТ» и «Гобелен» из категории «СТИЛИ» должен давать только продукты с бежевым + гобеленом и черным + гобеленом.

Я подумываю о предложении WHERE, которое проверяет: если какие-либо из флажков COLOR отмечены, то строите строку со значениями этих флажков в строковую переменную WhereClauseColor, используя значения флажка WhereCluaseColor + =;

если установлены какие-либо флажки STYLES, то с помощью другой переменной с именем WhereClauseStyles - как в категории Color.

Наконец, создайте строку sql с именем WhereClause: if WhereClauseColor! = ""тогда поле WhereClause + = AND 'color' в db СОДЕРЖИТ WhereClauseColor;

аналогичная вещь для стилей.

Но мне не повезло.Может быть, мне нужен совершенно другой подход.Жаль, что клиент хочет, чтобы продукты были флажками, чтобы разрешить множественный выбор в каждой категории.

WhereClause = "SELECT * FROM [xxxx] WHERE 0 = 1";
/////COLORS
// if (Request.Form["color_gold"] != null) { WhereClause += " OR  xxx.color = 'gold'"; }//// OLD CODE. . 08/04/11
if (Request.Form["color_spice"] != null) { WhereClause += " OR  CONTAINS (xxxx.color,'spice')"; }/// ## NEW CODE: NOTE CONTAINS. . 08/04/11

Ответы [ 5 ]

0 голосов
/ 21 октября 2011

Я работал над библиотекой под названием QBuilder, чтобы немного упростить этот тип динамического создания SQL. Это может быть полезным для вас.

http://qbuilder.codeplex.com/

0 голосов
/ 08 августа 2011
private List<string> arrColors = new List<String>();
private List<string> arrStyles = new List<String>();   

if (Request.Form["color_spice"] != null) { 
  arrColors.Add("spice"); }/// ## NEW CODE: NOTE CONTAINS. . 08/04/11

if (Request.Form["color_gold"] != null) { arrColors.Add("gold"); }

string sql = "select * from ado_products_fabrics where [color] in('";
       sql += string.Join("','", this.arrColors.ToArray());
       sql += "')";
       sql += " AND [style] in('";
       sql += string.Join("','", this.arrStyles.ToArray());
       sql += "')";

WhereClause = sql;/
0 голосов
/ 08 августа 2011

Я точно не знаю, почему вы используете Request.Form. Что-то вроде if (chkSpice.Checked) было бы намного более читабельным.

Если вам нужно сохранить свой SQL в коде и не можете использовать хранимую процедуру, то это один из способов сделать это. Вы не принимаете пользовательский ввод и не передаёте его в SQL, поэтому нет риска внедрения SQL.

Если вы знаете, какие ваши стили и цвета будут названы в базе данных, оператор SQL IN будет гораздо более эффективным.

string styles = String.Empty;
string colors = String.Empty;

if (chkTapestry.Checked)
    styles = "'Tapestry'";
else if (chkRug.Checked)
    styles += ",'Rug'";


if (chkBlack.Checked)
    colors = "'Black'";
else if (chkBeige.Checked)
    colors += ",'Beige'";

string sql = "SELECT * FROM [X]";

if (styles.Length > 0 && colors.Length > 0)
    sql += String.Format(" WHERE [Style] IN ({0}) AND [Color] IN ({1})", styles, colors);
else if (styles.Length > 0)
    sql += String.Format(" WHERE [Style] IN ({0})", styles);
else if (colors.Length > 0)
    sql += String.Format(" WHERE [Color] IN ({0})", colors);

Выше приведен довольно ручной подход к сборке стилей и цветов и использует прискорбное жесткое кодирование имен стилей и цветов. Лучшим дизайном может быть:

  1. Выберите все цвета из базы данных. Сохраните их в DataTable.
  2. DataСвязать цвета DataTable с элементом управления CheckBoxList для отображения цветов на странице.
  3. Выберите все стили из базы данных. Сохраните их в другой таблице данных.
  4. Привязка стилей DataTable к элементу управления CheckBoxList для отображения стилей на странице.

Затем в PostBack:

  1. Перезагрузите ваши таблицы данных со значениями из базы данных. Примите небольшой риск того, что список цветов изменился с момента рендеринга вашей страницы, или сохраните DataTable в переменной Session между постами, чтобы уменьшить риск.
  2. Перезагрузите ваши стили DataTable.
  3. Перебирайте по цветам элементы CheckBoxList в цикле for. Для каждого выбранного элемента используйте индекс цикла for, чтобы получить тот же индекс строки из DataTable. Получите название цвета из DataRow и добавьте его в свой список цветов для использования в части Color IN (...) вашего предложения WHERE. Это гарантирует, что вы используете значение из вашей базы данных, а не значение, которое может быть подделано пользователем.
  4. Перебирайте элементы стиля CheckBoxList в цикле for, выполняя те же действия, что и цвета.
  5. Соберите предложение WHERE, как я делал в примере кода.
  6. Выполните запрос к вашей базе данных и обработайте набор результатов.

Пример кода:

protected DataTable dtColors
{
    get
    {
        if (Session["fabrics-dtColors"] == null)
            Session["fabrics-dtColors"] = FetchDataTable("SELECT DISTINCT Color FROM X ORDER BY Color");
        return (DataTable)Session["fabrics-dtColors"]; 
    }
}

protected DataTable dtStyles
{
    get
    {
        if (Session["fabrics-dtStyles"] == null)
            Session["fabrics-dtStyles"] = FetchDataTable("SELECT DISTINCT Style FROM X ORDER BY Style");
        return (DataTable)Session["fabrics-dtStyles"]; 
    }
}

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        cblColors.DataSource = dtColors;
        cblColors.DataBind();

        cblStyles.DataSource = dtStyles;
        cblStyles.DataBind();
    }
}

protected void btnSearch_OnClick(object sender, EventArgs e)
{
    string colors = String.Empty;
    string styles = String.Empty;
    string sql = "SELECT * FROM [X]";

    if (cblColors.SelectedIndex > -1)
    {
        for (int i = 0; i < cblColors.Items.Count; i++)
        {
            if (cblColors.Items[i].Selected)
            {
                colors += String.Format("'{0}',", dtColors.Rows[i][0]);
            }
        }

        colors = colors.TrimEnd(',');
    }

    if (cblStyles.SelectedIndex > -1)
    {
        for (int i = 0; i < cblStyles.Items.Count; i++)
        {
            if (cblStyles.Items[i].Selected)
            {
                styles += String.Format("'{0}',", dtStyles.Rows[i][0]);
            }
        }

        styles = styles.TrimEnd(',');
    }

    if (styles.Length > 0 && colors.Length > 0)
        sql += String.Format(" WHERE [Style] IN ({0}) AND [Color] IN ({1})", styles, colors);
    else if (styles.Length > 0)
        sql += String.Format(" WHERE [Style] IN ({0})", styles);
    else if (colors.Length > 0)
        sql += String.Format(" WHERE [Color] IN ({0})", colors);

    GetSearchResults(sql);
}
0 голосов
/ 08 августа 2011

Создание таблиц в коде вашего приложения из различных вариантов: SelectedColors, Selected Styles, .... Затем передайте их как параметры хранимой процедуре, которая использует их в предложении WHERE:

where ( Color in (select Color from SelectedColors) or
     not exists ( select Color from SelectedColors ) ) and ...

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

Это позволит вам иметь несколько вариантов выбора и предотвратить атаки с использованием SQL-инъекций.

0 голосов
/ 07 августа 2011

Пытались ли вы сначала создать такой запрос выбора SQL, который вам необходим в SSMS, чтобы получить правильный синтаксис, чтобы, когда вы начинаете создавать динамический запрос, вы, по крайней мере, теперь, на что нацеливаетесь? Вот как я бы смотрел на это.

Вы также можете сделать все это в SQL с временными таблицами, где первый запрос принимает первый выбор флажков (передается в качестве параметров хранимому процессу, а следующий набор флажков обрабатывается в следующем разделе). вашего сохраненного процесса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...