Parameterize WHERE Clause dans la requête

Environnement:

  • C #
  • Visual Studio 2012
  • .NET Framework 3.5

salut

Pourrais-je paramétrer la clause where dans SQL Server?

Dans mon scénario, une fois qu'une clause WHERE Ssortingng est input, l'application la concaténera à l'autre partie de la requête et s'exécutera dans SQL Server puis returnnera le résultat.

Par exemple,

  • Entrées user "[CookingTime] <30 et [Coût] <20"
  • Application crée une requête "select [RecipeID] à partir de [Recipes] où [CookingTime] <30 et [Cost] <20" et s'exécute dans SQL Server.
  • L'application renvoie le résultat à l'user.

Pour des raisons de security, je voudrais faire WHERE CLAUSE comme paramètre. Mais je n'ai aucune idée de comment réaliser.

Merci d'avance.

Toute la clause WHERE en tant que paramètre sera victime d'une injection sql de quelque façon que ce soit. Pour éviter cela, vous feriez mieux de:

Configurez les permissions appropriées. Donc, même dans le cas d'un user SQL injecté ne peut pas accéder à quelque chose qui n'est pas accordé. Dans ce cas, l'exemple de @Dhaval est meilleur, car la génération sql dymanic encapsulée dans une procédure stockée nécessite less d'permissions pour s'exécuter.

Vérifiez la déclaration pour l'injection sql. La méthode la plus simple consiste à searchr des points-virgules afin d'éviter d'autres instructions dans le lot. Une manière plus complexe et plus précise consiste à utiliser l'parsingur DOM t-sql. Par exemple:

using Microsoft.SqlServer.TransactSql.ScriptDom; TSql110Parser parser = new TSql110Parser(true); IList<ParseError> errors = null; var condition = "a > 100; delete from [Recipes]"; var script = parser.Parse(new SsortingngReader("select [RecipeID] from [Recipes] where " + condition), out errors) as TSqlScript; if (errors.Count > 0) { throw new Exception(errors[0].Message); } foreach (var batch in script.Batches) { if (batch.Statements.Count == 1) { var select = batch.Statements[0] as SelectStatement; if (select != null) { QuerySpecification query = select.QueryExpression as QuerySpecification; if (query.WhereClause is BooleanBinaryExpression) { ... } } else { throw new Exception("Select statement only allowed"); } } else { throw new Exception("More than one statement detected"); } } 

Voilà comment cela peut être fait

 ssortingng commandText = "UPDATE Sales.Store SET Demographics = @demographics " + "WHERE CustomerID = @ID;"; using (SqlConnection connection = new SqlConnection(connectionSsortingng)) { SqlCommand command = new SqlCommand(commandText, connection); command.Parameters.Add("@ID", SqlDbType.Int); command.Parameters["@ID"].Value = customerID; // Use AddWithValue to assign Demographics. // SQL Server will implicitly convert ssortingngs into XML. command.Parameters.AddWithValue("@demographics", demoXml); try { connection.Open(); Int32 rowsAffected = command.ExecuteNonQuery(); Console.WriteLine("RowsAffected: {0}", rowsAffected); } catch (Exception ex) { Console.WriteLine(ex.Message); } } 

Vous pouvez créer une requête dynamic dans le server SQL et passer le paramètre de C #

Quelque chose comme ça

 Create Procedure usp_Test @WhereCond Varchar(max) AS Bgein Set NoCount ON Declare @SQLQuery AS Varchar(max) Set @SQLQuery = 'Select * From tblEmployees where ' + @WhereCond Execute sp_Executesql @SQLQuery End 

C # Code pour exécuter la procédure

 DataSet ds = new DataSet(); using(SqlConnection conn = new SqlConnection("ConnectionSsortingng")) { SqlCommand sqlComm = new SqlCommand("usp_Test", conn); sqlComm.Parameters.AddWithValue("@WhereCond", WhereCond); sqlComm.CommandType = CommandType.StoredProcedure; SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = sqlComm; da.Fill(ds); } 

Je suppose que la question originale voulait savoir comment le faire dynamicment à partir de l'input de l'user et ensuite utiliser le bon paramètre sql pour faire la requête.

Pour l'utilisation du paramètre sql, normalement ce que je fais est d'utiliser une méthode auxiliaire générique, un exemple rapide (non testé):

 public static class SqlHelpers { public static IEnumerable<T> ExecuteAdhocQuery<T>(SqlConnection con, ssortingng sql, CommandType cmdType, Func<SqlDataReader, T> converter, params SqlParameter[] args) { try { using (SqlCommand cmd = new SqlCommand(sql, con) { CommandType = cmdType }) { cmd.Parameters.AddRange(args); if (con.State != ConnectionState.Open) { con.Open(); } var ret = new List<T>(); using (SqlDataReader rdr = cmd.ExecuteReader()) { while (rdr.Read()) { ret.Add(converter.Invoke(rdr)); } } return ret; } } catch (Exception e) { // log error? Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); throw e; // handle exception... } } public void Test() { using (SqlConnection con = new SqlConnection("connection ssortingng here")) { var data = ExecuteAdhocQuery(con, "SELECT ID, Name FROM tblMyTable WHERE ID = @Id and Status = @Status;", CommandType.Text, (x) => new { Id = x.GetInt32(0), Name = x.GetSsortingng(1) }, new SqlParameter("@Id", SqlDbType.Int) { Value = 1 }, new SqlParameter("@Status", SqlDbType.Bit) { Value = true }); Console.WriteLine(data.Count()); } } } 

bien sûr, ce n'est que la lecture, pour l'insertion / mise à jour, des methods similaires pourraient également être créés.

Mais la partie compliquée est de savoir comment la rendre dynamic avec un nombre inconnu de conditions et la relation entre eux. Donc, une suggestion rapide est d'utiliser une méthode ou une class déléguée pour faire le travail. échantillon (non testé):

  public static Dictionary<ssortingng, SqlParameter> GetParamsFromInputSsortingng(ssortingng inputSsortingng) { var output = new Dictionary<ssortingng, SqlParameter>(); // use Regex to translate the input ssortingng (something like "[CookingTime] < 30 and [Cost] < 20" ) into a key value pair // and then build sql parameter and return out // The key will be the database field while the corresponding value is the sql param with value return output; } public void TestWithInput(ssortingng condition) { var parameters = GetParamsFromInputSsortingng(condition); // first build up the sql query: var sql = "SELECT Id, Name from tblMyTable WHERE " + parameters.Select(m => ssortingng.Format("{0}={1}", m.Key, m.Value.ParameterName)).Aggregate((m,n) => m + " AND " + n); using (SqlConnection con = new SqlConnection("connection ssortingng here")) { var data = ExecuteAdhocQuery(con, sql, CommandType.Text, (x) => new { Id = x.GetInt32(0), Name = x.GetSsortingng(1) }, parameters.Select(m => m.Value).ToArray()); } } 

pour la fonction statique GetParamsFromInputSsortingng, c'est juste un exemple. En fait, cela pourrait être très compliqué en fonction de vos besoins.

Par exemple, vous pouvez inclure l'opérateur (que ce soit>, <ou <>, …).

et vous pourriez également vouloir inclure les conjonctions entre les conditions, que ce soit AND ou OR.

Construire des classs déléguées pour faire le travail si c'est très compliqué.