I’m developing a server/client application in C#. In the earlier phases of development I was writing SQL codes each time and it caused spaghetti code. Now I’m trying to make it clean. My question is: How can I write a general query generator function with dynamic parameters?
x
private void button3_Click(object sender, EventArgs e)
{
try
{
SqlCommand cmd= new SqlCommand();
cmd.CommandText = "INSERT INTO tbl(line, name, firstvalue, secondvalue)" +
"VALUES(@line, @name, @value, @secondvalue)";
cmd.Parameters.AddWithValue("@line", comboBox4.Text);
cmd.Parameters.AddWithValue("@name", textBox2.Text);
cmd.Parameters.AddWithValue("@value", comboBox5.Text);
cmd.Parameters.AddWithValue("@secondvalue", comboBox6.Text);
cmd.Connection = Db.Db;
cmd.CommandType = CommandType.Text;
SqlDataReader dr = cmd.ExecuteReader();
MessageBox.Show("Saved");
}
catch (Exception ex)
{
MessageBox.Show(ex);
}
finally
{
Db.Close();
}
}
But I want to convert it into:
public void query(string commandText, params string[] parameters)
{
SqlCommand command = new SqlCommand();
command.CommandText = commandText;
foreach (var parameter in parameters)
//In this part, there can be lots of different queries and how can assign each parameter to relevant values
//Is there any change to assign them in order.
}
Advertisement
Answer
Well, if you insist on implementing such a routine (usually we use ORM) you have to parse the commandText
; the simplest (but not the best) implementation is regular expressions (we Match
parameter name within commandText
, then Zip
it with its value from parameters
):
using System.Linq;
using System.Text.RegularExpressions;
public void query(string commandText, params string[] parameters) {
using (SqlCommand command = new SqlCommand()) {
command.Connection = myConnection; //TODO: put the right connection here
command.CommandText = commandText;
var prms = Regex
.Matches(commandText, @"b@[A-Za-z_][A-Za-z_0-9]*b")
.Cast<Match>()
.Zip(parameters, (match, value) => new {
name = match.Value,
value
});
foreach(var prm in prms)
command.Parameters.AddWithValue(prm.name, prm.value);
// Just execute; we have nothing to read (ExecuteReader)
command.ExecuteNonQuery();
}
}
Edit: If you want / ready to specify parameters’ names, not only values you can try Tuple
s: for c# 7.0+
public void query(string commandText, params (string, object)[] parameters) {
foreach (var prm in parameters)
command.Parameters.AddWithValue(prm.Item1, prm.Item2);
}
usage
query(sql,
("@line", comboBox4.Text),
("@name", textBox2.Text),
("@id", 123), // please, note integer value
("@money", 456.78d),
);
for C# 6.0-:
public void query(string commandText, params Tuple<string, object>[] parameters) {
foreach (var prm in parameters)
command.Parameters.AddWithValue(prm.Item1, prm.Item2);
}
query(sql,
Tuple.Create("@line", comboBox4.Text),
Tuple.Create("@name", textBox2.Text),
);