2013-05-28 6 views
2

Я искал и искал ответ для этого, и я не могу его найти. У меня есть проверочный список, в котором пользователь будет выбирать проблемы, которые они испытывают с помощью своего компьютера. В отмеченном списке вы увидите такие вещи, как ... Медленный, Вирусы, Плохой жесткий диск ... и на основе того, что они выбирают, я расскажу им примерную стоимость ремонта. В настоящее время это, как я строю мой запрос:Создание динамического SQL-запроса из VB.NET

Dim mIssues As String = "" 

For i = 0 To lstIssues.CheckedItemsCount - 1 
If mIssues = "" Then 
    mIssues = String.Format("IssueName = '{0}'", lstIssues.CheckedItems(i)) 
Else 
    mIssues = String.Format("{0} OR IssueName = '{1}'", mIssues, lstIssues.CheckedItems(i))    
End If 
Next 

Приведенный выше код будет выглядеть, чтобы увидеть, сколько проблем они выбрали. Если они выбрали только одну проблему, она вернет такую ​​строку: IssueName = 'What they they they selected'. Если они выбрали более одной проблемы, она вернет строку, такую ​​как: IssueName = 'What they they they selected' ИЛИ ​​IssueName = 'Второй выбор'. Поэтому в основном я добавлю OR между всеми выборами, если они выберут более одной проблемы. Я делаю это, чтобы динамически строить предложение where, которое было в моем запросе.

Вот мой запрос:

Dim mySQL As String = "SELECT IssueID, IssueTypeID, IssueName, IssueDescription, " _ 
    & "CustomerID, IndividualCost, GroupCost, Active, ChargeType " _ 
    & "FROM (SELECT IssueID, IssueTypeID, IssueName, IssueDescription, " _ 
    & "CustomerID, IndividualCost, GroupCost, Active, ChargeType " _ 
    & "FROM(cfg_Issues) " _ 
    & "WHERE " & mIssues & " " _ 
    & "GROUP BY IssueID, IssueTypeID, IssueName, IssueDescription, CustomerID, " _ 
    & "IndividualCost, GroupCost, Active) " _ 
    & "ORDER BY IndividualCost DESC, GroupCost ASC;" 

Как вы можете видеть мой, где положение исходит из первой части кода. Мой вопрос в том, есть ли лучший способ сделать это ??? Я знаю, что должен быть лучший способ создать динамический запрос предложения where, и я хотел бы посмотреть, как это сделать. Спасибо за любые рекомендации, которые вы можете мне помочь.

+0

Сначала прочитайте информацию о параматтизированных запросах, таких как [это] (http://www.blakepell.com/Main/BlogEntry.aspx?EntryID=054ce25a-1410-445c-807a-cc10bc20502d). Вы могли бы использовать предложение 'IN()' вместо того, чтобы делать много «a ИЛИ b» и т. Д., Немного сложнее сохранить параматизацию, но не [невозможно] (http://stackoverflow.com/questions/303149/parameterized- queries-with-like-in-conditions) –

+0

Что вы делаете прямо сейчас, если уязвимы для SQL-инъекций. Можно было бы обмануть ваше приложение, заменив произвольный текст на запрос, что позволит мне выполнить любой код sql в вашей базе данных, который я хочу. –

+0

Является ли динамический SQL вариантом ... Я могу показать вам, как это сделать. – logixologist

ответ

7

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

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

Dim mIssues As StringBuilder = new StringBuilder() 

For i = 0 To lstIssues.CheckedItemsCount - 1 
    mIssues.AppendFormat("IssueName = '{0}' OR ", lstIssues.CheckedItems(i)) 
Next 

' I suppose that you have a check in place to not allow to run this query if you don't have at 
' least one element checked in the list (if not the WHERE condition will fail)' 
mIssues.Length -= 4 

Это удалит IF внутри цикла и, чтобы удалить лишний OR, это достаточно уменьшить длину экземпляра StringBuilder при выходе из цикла.
В тексте запроса StringBuilder может вернуть свою внутреннюю строку, используя

mIssues.ToString 

Вы также можете попробовать использовать выражение SQL с использованием кода, как этот

Dim mIssues As StringBuilder = new StringBuilder() 

For i = 0 To lstIssues.CheckedItemsCount - 1 
    mIssues.AppendFormat("'{0}', ", lstIssues.CheckedItems(i)) 
Next 

' I suppose that you have a check in place to not allow this query if you don't have at 
' least one element checked in the list (if not the WHERE condition will fail)' 
mIssues.Length -= 2 
mIssues.Insert(0, "IssueName IN(") 
mIssues.Append(")") 
+0

Спасибо, Стив! Я попробую ваше предложение завтра утром, когда я вернусь в офис. Спасибо за помощь!!! –

0

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

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

CREATE PROCEDURE p_getIssues 
as 

/*This is where you will place all your input parameters like this 
@paramname1 datatype, 
@paramname1 datatype, 

@mIssues varchar(max) example: virus = 1 and slowcomp = 1 


*/ 
BEGIN 

DECLARE @SQL as varchar(max) 
SET @SQL = 'SELECT * FROM tablename where ' + @mIssues 

EXEC (@SQL) 

END 

Примечание: Если вы когда-нибудь debug sproc ... закомментируйте EXEC и ADD A PRINT (@SQL) , и вы можете увидеть, какой SQL запускается sproc.

Если вам нужно идти динамично, это всегда предпочтительный метод. Также на стороне примечание sql внутри вашего кода VB.NET не рекомендуется IMHO, потому что тогда с точки зрения масштабируемости и обновляемости, если бы вы добавляли больше сервисов, вам нужно вытолкнуть новый код VB.NET.Вместо этого вы входите в SQL, и вы можете внести изменения, и все готово!

+1

Спасибо! В прошлом я всегда загружал свои приложения с кодом, и теперь я пытаюсь найти этот баланс между приложением и сервером db. Я использую mySQL как БД, и я нахожу незначительные различия между этим и SQL Server. –

+0

Я твердо убежден в том, что все вызовы базы данных не содержат кода. Я также рекомендую использовать Stored Procs для вызова базы данных. Wether вы выбираете SQL или MySQL - это ваш вызов, но сохраняйте код базы данных отдельно от кода приложения. – logixologist

Смежные вопросы