In this article, I will represent different techniques to build and make use of parameterized queries. The first way is the classical one, and I mean by that the ADO.Net technique. Then I'll expose the second one using the new technology, namely DLINQ.
First, the customers table that will be used as data source is represented as under:
Figure 1
Say that we want to build a parameterized query that enables to select information about different customers those correspond to the country entered by the user. To do this, let's first leverage the UI. For this reason, we create a new windows project named ParameterizedQuery. Then we add a data grid view, a group box and a combo box into the Form1 and we dispose them as follow:
Figure 2
The ADO.Net classic technique:
The data source used to leverage this example is the Customers table located in the NorthWind SQL server data base sample that is downloadable from http://www.microsoft.com/downloads/details.aspx?FamilyID=06616212-0356-46A0-8DA2-EEBC53A68034&displaylang=en
After downloading and deploying the msi file, the NorthWind data base could be reached in C:\SQL Server 2000 data bases\NORTHWIND.MDF
In order to build a more secure system, we have to query data using stored procedures via SQL parameters rather than querying tables via inputs from the user input control such as a given text box and that for the only purpose to avoid SQL injections queries.
First, let's create the stored procedure that enables querying data according to the country entered by the user via the ComboBox1 control. We can either use Visual Studio or Microsoft SQL Server to leverage that. And, indeed, this is the stored procedure core
ALTER PROCEDURE dbo.StoredProcedure1
(
@Country nvarchar(15)
)
AS
/* SET NOCOUNT ON */
SELECT CompanyName, ContactName, ContactTitle, Address, City, PostalCode, Phone, Fax
FROM Customers
WHERE Country = @Country
SqlConnection oConnection;
//The parameter used to enter data via UI input control
SqlParameter CountryParam = new SqlParameter("@Country", SqlDbType.NChar);
//The sql command
SqlCommand cmdDataGrid = new SqlCommand("StoredProcedure1");
//The Source is the data set used as the data grid view data source
DataSet Source = new DataSet();
SqlDataAdapter oAdapter = new SqlDataAdapter();
And then we implement the load event handler with this code:
private void Form1_Load(object sender, EventArgs e)
{
//Precise that the type of the data source is a stored procedure
cmdDataGrid.CommandType = CommandType.StoredProcedure;
//This list is used to populate the combo box later
List<string> oList = new List<string>();
//The connection must be initialized
oConnection = new SqlConnection();
//The connection string could be changed to fit given needs
oConnection.ConnectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=" +
@"C:\SQL Server 2000 Sample Databases\NORTHWND.MDF';Integrated Security=True;" +
@"Connect Timeout=30;User Instance=True";
//The try here enables to catch sql exceptions when opening the connection
try
{
oConnection.Open();
//This command is used to select all countries in the Customers data table
SqlCommand cmdCombo = new SqlCommand("SELECT DISTINCT Country FROM Customers", oConnection);
//The reader here is used to populate the oList
SqlDataReader oReader = cmdCombo.ExecuteReader();
try
{
while (oReader.Read())
{
oList.Add(oReader[0].ToString());
}
}
finally { oReader.Close(); }
//Set the data source of the data set Source as oList
comboBox1.DataSource = oList;
}
catch (SqlException caught)
{
MessageBox.Show(caught.Message);
}
finally
{
oConnection.Close();
}
}
After that, we implement the comboBox1 SelectedIndexChanged event handler with the following code:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
//Set the connection
cmdDataGrid.Connection = oConnection;
//Set the sql parameter value as the selected comboBox1 text
CountryParam.Value = comboBox1.Text;
//Add the sql parameter to the command parameters collection
cmdDataGrid.Parameters.Add(CountryParam);
//Set the command of the adapter later used to fill the Source
oAdapter.SelectCommand = cmdDataGrid;
//Fill the Source data source used later as data source for the
//dataGridView1
oAdapter.Fill(Source);
dataGridView1.DataSource = Source;
dataGridView1.DataMember = Source.Tables[0].TableName;
}
finally
{
//As we don't need to save them in this example
cmdDataGrid.Parameters.Clear();
}
}
[Table(Name = "Customers")]
class Customer
{
[Column(Name = "CustomerID", IsPrimaryKey = true)]
public string Identifier;
[Column(Name = "CompanyName")]
public string CompanyName;
[Column(Name = "ContactName")]
public string ContactName;
[Column(Name = "Address")]
public string Address;
[Column(Name = "City")]
public string City;
[Column(Name = "Region")]
public string Region;
[Column(Name = "Country")]
public string Region;
}
//Constructor
public NorthWind():base(@"Data Source=STANDARD;Initial Catalog=" +
@"C:\SQL SERVER 2000 SAMPLE DATABASES\NORTHWND.MDF';" +
"Integrated Security=True")
{
}
//Returns the Customer table from the Northwind data base
public Table<Customer> GetCustomerTable()
{
return this.GetTable<Customer>();
}
}
/* The derived object from Data context
* is used to define an instance used later
to get the customer table*/
NorthWind oNorthWind;
/*The customer table variable */
Table<Customer> Customers;
/* This dataset will be used
as datagrid view data source later*/
DataSet Source;
/*The oAdapter will be used to populate
the data set Source*/
SqlDataAdapter oAdapter;
/*This command will be the result of the
Onversion of the dlinq query into sqlcommand
type*/
SqlCommand oCommand;
Then we implement the Form1 load event handler as follow:
private void Form1_Load(object sender, EventArgs e)
{
oAdapter = new SqlDataAdapter();
oNorthWind = new NorthWind();
//Custmer is set thanks to the NorthWind object method
Customers = oNorthWind.GetCustomerTable();
/* This query serves as data source for the
combo box1, Distinct is used to avoid the redendance */
var query = (from cust in Customers
select cust.Country).Distinct();
//Populate the combo box
foreach (string c in query)
comboBox1.DataSource = query;
}
IQueryable<Customer> Query;
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//An extention method is used here to query the Customer table
Query = oNorthWind.GetCustomerTable().Where(cus => cus.Country == comboBox1.Text);
/* The get GetCommand method enables to get a
boxed command object that we have to unboxe it using "as SqlCommand" */
oCommand = oNorthWind.GetCommand(Query) as SqlCommand;
//The rest is easy to undersand ........
oAdapter.SelectCommand = oCommand;
Source = new DataSet();
oAdapter.Fill(Source);
dataGridView1.DataSource = Source;
dataGridView1.DataMember = Source.Tables[0].TableName;
}