How to add multiple parameters to SQL command in one statement? - c#

I have six lines of parameters like this:
cmd.Parameters.AddWithValue("#variable1", myvalue1);
cmd.Parameters.AddWithValue("#variable2", myvalue2);
cmd.Parameters.AddWithValue("#variable3", myvalue3);
and so on.
Is there any way to compress this a bit without directly inserting in the cmd.CommandText?
Edit: I guess I could have used a good old fashioned array. I've decided to stick with this though.

As far as I know, your code is the most compact possible in term of lines count, however you could use the List<SqlParameter> with the object initializer syntax to have just one line terminated by a semicolon to build your parameter list, then pass that list as the array of parameters expected by the AddRange method
List<SqlParameter> prm = new List<SqlParameter>()
{
new SqlParameter("#variable1", SqlDbType.Int) {Value = myValue1},
new SqlParameter("#variable2", SqlDbType.NVarChar) {Value = myValue2},
new SqlParameter("#variable3", SqlDbType.DateTime) {Value = myValue3},
};
cmd.Parameters.AddRange(prm.ToArray());
Notice that with this approach you need to define correctly the datatype of the parameter. In my example I have used some arbitrary types to show the correct syntax
A bit off-topic, by I think that in this general context is interesting to point out that AddWithValue is not to be considered when you want to get the best performance possible.
In this article on MSDN How data access code affects database perfomance is well explained why one should avoid the AddWithValue method for performance reasons.
In short, using AddWithValue could be a problem for the Sql Server Optimizer because the parameters of type string are passed with the size equal to the current length of the string. But this will force the Sql Server Optimizer to discard the query plan created for a previous identical call but with a string of different length.
It is better to call the SqlParameter constructor specifying the type and the size of the parameter and don't worry how to compress the size of the calls.

I took the question literally: "...in one statement" :)
Steve code is nice but it can be simplified a bit more using the most canonical SqlParameter constructor and implicit arrays declaration:
cmd.Parameters.AddRange(new []
{
new SqlParameter("#variable1", myValue1),
new SqlParameter("#variable2", myValue2),
new SqlParameter("#variable3", myValue3),
});

I think this will read very nicely as a one liner like this:
Usage:
// One liner to create and set SqlCommand parameters
cmd.SetParameters(Parameter("#variable1", myvalue1), Parameter("#variable2", myvalue2), Parameter("#variable3", myvalue3));
To support the one liner you need to create a function to wrap the Sql Parameter as a semantic bundle (Tuple like) as follows:
public SqlParameter Parameter(string name, object value)
{
return new SqlParameter(name, value);
}
Create a static class with an extension method to give us the syntactic sugar we are looking for. Notice the use of the params keyword which allows the multiple parameters in the above call to SetParameters.
public static class SqlDataUtils
{
public static void SetParameters(this SqlCommand command, params SqlParameter[] parameters)
{
command.Parameters.AddRange(parameters);
}
}
This answer is inspired by the accepted answer to Key value pairs in C# Params by Bryan Watts

Just for argument's sake, using the code example you gave where the stored proc variables are literally named variabe1, variable2, etc... you could do something like this:
string[] myValues = new string[] { "myvalue1", "myvalue2", "myvalue3", "myvalue4", "myvalue5", "myvalue6" };
for (int i = 0; i < 6; i++) { cmd.Parameters.AddWithValue("#variable" + (i + 1),myValues[i]); }
2 lines of ugly code... LOL
A loop like this may come in handy if you had say 25 - 50 values, though I don't see that very often. And you could use 2 arrays one for the variable names and one for the values, as long as the indexes match up, then this would work:
string[] myVarNames = new string[] { "variable1", "variable2", "variableThree", "variable4our", "variableFIVE", "variableSIX" };
string[] myValues = new string[] { "myvalue1", "myvalue2", "myvalue3", "myvalue4", "myvalue5", "myvalue6" };
for (int i = 0; i < 6; i++)
{
cmd.Parameters.AddWithValue("#" + myVarNames[i], myValues[i]);
}

Related

Is it safe to reuse a SqlDataRecord?

When implementing table-valued parameters, one of the most common ways to generate an IEnumerable<SqlDataRecord> for use by the parameter is code like this (e.g., https://stackoverflow.com/a/10779567/18192 ):
public static IEnumerable<SqlDataRecord> Rows(List<int> simpletable)
{
var smd = new []{ new SqlMetaData("id", SqlDbType.Int)};
var sqlRow = new SqlDataRecord(smd);
foreach (int i in simpletable)
{
sqlRow.SetInt32(0, i);
yield return sqlRow;
}
}
//...
var param = sqlCmd.Parameters.AddWithValue("#retailerIDs", Rows(mydata));
param.SqlDbType = SqlDbType.Structured;
param.TypeName = "myTypeName";
This code does seem to work. While reusing SqlMetaData does not set off too many alarm bells, declaring the SqlDataRecord outside the foreach loop feels incredibly suspicious to me:
A mutable object is modified and then yielded repeatedly.
As an example of why this is concerning, calling var x = Rows(new[] { 100, 200}.ToList()).ToList().Dump() in LinqPad spits out 200,200. This approach seems to rely on an implementation detail (that rows are processed individually), but I don't see any documentation which promises this.
Is there some mitigating factor which renders this approach safe?
This approach seems to rely on an implementation detail (that rows are
processed individually), but I don't see any documentation which
promises this.
Is there some mitigating factor which renders this approach safe?
As user1249190 points out, Reusing SQLDataRecord is explicitly recommended in the remarks section of https://learn.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.server.sqldatarecord#remarks :
This class is used together with SqlPipe to send result sets to the
client from managed code stored-procedures. When writing common
language runtime (CLR) applications, you should re-use existing
SqlDataRecord objects instead of creating new ones every time.
Creating many new SqlDataRecord objects could severely deplete memory
and adversely affect performance.
Obviously this recommendation does not apply to usage across threads: The documentation also explicitly warns that "Any instance members are not guaranteed to be thread safe."
If you don't need it outside of the foreach loop at all, I don't see why you would want to re-use it.
I found this question Is there a reason for C#'s reuse of the variable in a foreach? which links to this answer in another question Is it better coding practice to define variables outside a foreach even though more verbose? where Jon Skeet answered saying:
There's no advantage to declaring the variables outside the loop, unless you want to maintain their values between iterations.
(Note that usually this makes no behavioural difference, but that's not true if the variables are being captured by a lambda expression or anonymous method.)
void Main()
{
//This code proves that the object is being modified.
Thing prevRow = null;
foreach (var curRow in Rows(new List<int>() { 1, 2, 3 }))
{
Console.WriteLine(curRow);
Console.WriteLine(prevRow);
prevRow = curRow;
}
//Because the object is modified instead of a new object being returned,
// this code does something unexpected; it returns the same object 3
// times! Instead of three unique objects representing the values 1, 2, 3.
var rowsAsList = Rows(new List<int>() { 1, 2, 3 }).ToList();
foreach (var curRow in rowsAsList)
{
Console.WriteLine(curRow);
}
}
public class Thing
{
public int i;
}
IEnumerable<Thing> Rows(List<int> simpletable)
{
// Bad: Reusing the object will cause problems. Comment out the next line to fix the bug.
var sqlRow = new Thing() {i=-1};
foreach (int x in simpletable)
{
// Good: Do this instead! Uncomment the following line to fix the bug.
// var sqlRow = new Thing() {i=x};
sqlRow.i = x;
yield return sqlRow;
}
}

Passing list members into a function

How would I pass a list of values into a function, where the values are already stored in a list and the function isn't the same every time?
To explain, I've got a list of several different types of custom objects (A List<object> to make this work) and I want to pass those objects into a function. However, the function isn't always the same. I could have several different functions, and, assuming that List's contents will always match the function's input variables, I want to be able to pass the list's contents into my function.
The following code is an example of what might work, but for one flaw:
List<object> myListOfVariables = new List<object>();
myListOfVariables.Add("Hello, world!");
myListOfVariables.Add(10);
void SayHelloXTimes(string helloString, int x) {
for(int i = 0;i<x;i++) {
print(helloString)
}
}
SayHelloXTimes(myListOfVariables[0], myListOfVariables[1]);
Now, since I know my list will always contain the right amount of variables in the right positions, that would work, if I only had one function. But the problem is, I need to expand this so I could take apart my list and pass it into functions with different amounts of parameters.
For other reasons, I know my list will always have the right amount of variables in the right positions, so we don't need to worry about that. I'll also know the name of the function I need to pass my values into. I suppose I could do a load of if statements depending on the length of my list, like this:
if (myListOfVariables.Length == 2) {
SayHelloXTimes(myListOfVariables[0], myListOfVariables[1]);
}
else if (myListOfVariables.Length == 3) {
SayHelloXTimesForY(myListOfVariables[0], myListOfVariables[1], myListOfVariables[2]);
}
However, this (obviously) is really clunky code and I'd like to avoid it at all costs. Is there another solution to my problem? I know this is really confusing, but I did my best to explain it. If you're still confused as to what I'm trying to do, please let me know.
And no, this is not a homework problem. ;)
I think want you want to do can be done using reflection. Look at MethodBase.Invoke Method
All you have to do is add all the parameters in the order the function expects to an object array.
class Program
{
public static void SayHelloXTimes(string helloString, int x)
{
for (int i = 0; i < x; i++)
{
Console.WriteLine(helloString);
}
}
static void Main(string[] args)
{
MethodInfo Method = typeof(Program).GetMethod("SayHelloXTimes");
Method.Invoke(null, new object[] { "foo", 3 });
Console.ReadLine();
}
}
You want params:
void SayHelloXTimes(params string[] list) {
for(int i = 0;i<list.Length;i++) {
print(list[i])
}
}
SayHelloXTimes("Hi", "Hi", "Hi"); // legal
SayHelloXTimes("Hi"); // legal
SayHelloXTimes("Hi", "Hi", "Hi", "Hi", "Hi", "Hi"); // still legal
If this were my application, I would create a parameter class to hold the list values.
You could pass the list into the class' constructor and either extract it into class-local properties (since you know the positions) or you could expose the values as readonly property directly from the list.
You can then just pass an instance of the parameter class to each of the methods and not have to worry about the number of parameters to the methods.

C# : Passing Parameters to a function via a 2d object array

I'm trying to write a neat little generic Sql method that will accept a SQL Query and a list of parameters, and return a result. I want to keep it neat enough that I can call it using one line from any other code.
Is there any really awesomely neat way of doing this? I don't want to create all the SqlParameters in the calling code, and I don't want to have to pass and split a string. In the past I've used a string[] array and accepted every odd member as a parameter name and every even as a param value but that's too easy to screw up when calling the method.
Ideally I'd love to do just this:
Data.SQL("Select * from Table where my_id = #my_id", { my_id = 1 });
I know that's a little unrealistic, So I tried this:
Data.SQL("Select * from Table where my_id = #my_id", new Object[,]{ { "my_id", 1 } });
However when I try and handle that on the other end, I get nothing but trouble:
public static Object SQL(String command, Object[,] parameters = null){
[ ... reusable SQL code here... ]
foreach(Object[] p in parameters){
cmd.Parameters.Add(new SqlParameter(p[0].ToString(), p[1].ToString());
}
}
Looks fine, but throws an error on the foreach statement
foreach (Object[] p in parameters)
Unable to cast object of type 'System.String' to type 'System.Object[]'
But I didn't pass it an array of System.String. What I passed was a 2D System.Object[]! Wasn't it?
Maybe this is just some small code problem, something stupid I'm doing wrong. It usually is. But I'm figuring you guys know some even neater way to do the above.
Ideally I'd love to do just this:
Data.SQL("Select * from Table where my_id = #my_id", { my_id = 1 });
I know that's a little unrealistic,
Well, in exactly that form, yes... but try this instead:
Data.SQL("Select * from Table where my_id = #my_id", new { my_id = 1 });
That will use an anonymous type for the argument, which you can examine by reflection. You probably only need a single parameter (i.e. it would be SQL(string sql, object parameters)) because you would pass multiple parameters in a single object:
Data.SQL("Select * from Table where my_id = #my_id and name = #name",
new { my_id = 1, name = "Jon" });
More alternatives:
If you're using C# 4, you might find dynamic typing useful; look at what Massive does for example.
As mentioned by Ray, you could pass in a Dictionary<string, object>; again, C# 3 makes this easier than otherwise:
Data.SQL("...", new Dictionary<string, object> {
{ "my_id", 1 },
{ "name", "Jon" }});
EDIT: As for the exact problem you're running into: you need to understand the difference between a rectangular array (e.g. Object[,]) and a jagged array (e.g. Object[][]). The latter is an array of arrays, which is how you're trying to use the parameter, but it's really only a rectangular array. Changing your parameter type to Object[][] may well fix that immediate problem - but personally I'd move to one of the approaches above. I'd also try to avoid making everything into a string, by the way.

Can parameters be generically accessed?

I have a lot of functions that look like this. Each has N arguments and each creates an SQLparamater array with each paramater being of this very similar form.
[WebMethod]
public static string accessServer(string dataField1, string dataField2, string dataField3) {
string value;
SQLParamater[] param = new SQLParameter[len] // len is the amount of arguments
param[0] = new SQLParameter("#dataField1", dataField1);
param[1] = new SQLParameter("#dataField2", dataField2);
param[2] = new SQLParameter("#dataField3", dataField3);
...
// do something with param
return value;
}
This looks like it can be done generically using a combination of Reflection and accessing the paramaters in a generic way.
Ideally a method of the form
public static SQLParamater[] getParams(someType paramaters)
and SQLParamater[] param = getParams(...)
I'm not sure how to pass on all the paramaters generically.
[Edit]
Note that the names of these datafields are important. It's not just an array of strings but rather a set of key/value pairs.
[/Edit]
You can use a function with variable arguments: name(params string[] arguments), so you can call, for example: name(arg1,arg2,arg3,arg4);
This has been asked about before (can't find that question though), the problem however is that while you can figure out the parameter names by using reflection MethodBase.GetCurrentMethod() you can't zip those names together with the parameter values because there's no way for you to access a parameter list of values.
There are other ways of trying to work around this very specific tiresome problem but I don't recommend doing it this way, it just doesn't make a lot of sense.
Now, given a method like this:
static void SomeMethod(string arg1, int arg2, object arg3)
{
}
You could do this:
static void Main()
{
var b = 123;
// this now becomes necessary as it's the only way of getting at the metadata
// in a presumable safe manner
Expression<Action> x = () => SomeMethod("a", b, "a" + b);
var args = GetArgs(x);
foreach (var item in args)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
And implement the GetArgs method like so (you still need a way of putting those values somewhere becuase the invocation never occurs):
static IDictionary<string, object> GetArgs(Expression<Action> x)
{
var args = new Dictionary<string, object>();
var m = (MethodCallExpression)x.Body;
var parameters = m.Method.GetParameters();
for (int i = 0; i < m.Arguments.Count; i++)
{
// an easy way of getting at the value,
// no matter the complexity of the expression
args[parameters[i].Name] = Expression
.Lambda(m.Arguments[i])
.Compile()
.DynamicInvoke();
}
return args;
}
You infer the collection of name/value pairs from the expression tree created by the compiler, it's doable but kind of odd.
I think your API design is flawed if you need this, you would better have one method, which accepts a collection of some sort.
Code duplication like this is almost never the correct way to get things done.
EDIT
On topic:
I guess you can get the values from the stack: http://www.thescarms.com/dotnet/StackFrame.aspx
we do it like this:
var dict=new Dictionary
{
{"#param1",value1},
{"#param2",value2},
{"#param3",value3},
{"#param4",value4},
....
};
DALayer.ExecuteProc("procName",dict);
In the ExecuteProc function you can iterate over Dictionary object and set params using KeyValuePair object. But if you have to setup the datatype, lengths etc for the parameters then you have to do more work like preparing the sql command to query about parameters or passing more complicated object as parameter that contains information about datatype, length and direction etc.

Simple way to transpose data before passing to functions?

This is one of the hardest questions I've ever had to title here on SO. :) Although the title might not make sense, hopefully the question itself will.
Let's say I have a data structure like a Dictionary<string, List<double>>, and that I have functions that then take List<double>s as a parameter:
Dictionary<string, List<double>> candy_positions = new Dictionary<string, List<double>>();
candy_positions.Add( "Godiva", new List<double> { 1.0, 2.0, 4.0 });
EatCandy( candy_positions["Godiva"]);
...
But now I have decided that I don't want to do it this way. I want to replace my Dictionary with a List<CandyPositions>, where CandyPositions looks something like this:
public class CandyPositions
{
public double Sees;
public double Godiva;
public double Lindt;
}
However, I really would like to leave EatCandy() alone. Obviously, the problem is now that my data doesn't lend itself to be passed directly into the method. Instead, I have to do something lame like:
List<CandyPositions> candy_positions = new List<CandyPositions>();
...
var positions = from x in candy_positions select x.Godiva;
EatCandy( positions.ToList());
every time I want to call the method. I'd prefer to be able to do this in a more simple way, like:
EatCandy( candy_positions.GetPositionsFor( "Godiva"));
where the parameter "Godiva" matches the property name in the CandyPositions class.
After writing this question, I've realized that it isn't really about transposing data -- that part of it can be handled by writing an extension method. The part I don't know how to do is to pass in a property name, so that the extension method can take this and associate it with a class's property. I don't want to pass in a string, either, mainly because this will open the door for all sorts of runtime errors. I know how to make this work by passing "Godiva" to my extension method. What I really want to pass in is something akin to CandyPositions.Godiva instead.
This question is probably a little confusing, so in summary, I would accept the best of two types of answers:
Is there a better way to deal with transposing data, than to use an extension method + some way of accessing a property name?
Is there a way to specify the property that I want my extension method to retrieve, other than by a string?
My current extension method looks like this:
public static List<double> GetPositions( this List<CandyPositions> positions, string candy_name)
{
return (from x in positions select x.GetType().GetProperty(candy_name).GetValue(x, null)).Cast<double>().ToList();
}
Well, you could use:
public static List<double> GetPositions(this List<CandyPositions> positions,
Func<CandyPositions, double> projection)
{
return positions.Select(projection).ToList();
}
and call it with:
EatCandy(candyPositions.GetPositions(x => x.Godiva));
On the other hand, if you can change EatCandy to accept an IEnumerable<double> instead, you don't need the extra method - you can just use:
EatCandy(candyPositions.Select(x => x.Godiva));
without writing an extra method at all.
EDIT: If you need to iterate over two sequences at once, there are two options:
If you're using .NET 4, you can use the Zip extension method.
Otherwise, you can basically write your own:
using (var iterator1 = sequence1.GetEnumerator())
using (var iterator2 = sequence2.GetEnumerator())
{
while (iterator1.MoveNext() && iterator2.MoveNext())
{
var value1 = iterator1.Current;
var value2 = iterator2.Current;
// Use the values here
}
}

Categories