C#: How to set a string as SqlParameter? - c#

I have a DataTable. How to set a certain value of it as one of my SqlParameters?
I receive this error message:
The SqlParameterCollection only accepts non-null SqlParameter type objects, not String objects.
Either I do:
myCommand.Parameters.Add("#managedBy");
myCommand.Parameters["#managedBy"].Value = comp.Rows[i][4].ToString();
myCommand.Parameters.Add("#modified_at");
myCommand.Parameters["#modified_at"].Value = DateTime.Now.ToString("MM/dd/yyyy");
myCommand.Parameters.Add("#cn");
myCommand.Parameters["#cn"].Value = comp.Rows[i][1].ToString();
or:
myCommand.Parameters.Add("#managedBy");
myCommand.Parameters["#managedBy"].Value = (SqlParameter)comp.Rows[i][4];
myCommand.Parameters.Add("#modified_at");
myCommand.Parameters["#modified_at"].Value = DateTime.Now.ToString("MM/dd/yyyy");
myCommand.Parameters.Add("#cn");
myCommand.Parameters["#cn"].Value = (SqlParameter)comp.Rows[i][1];
What am I missing? How to set the parameter from a DataTable?

The SqlParameterCollection.Add method overloads with one argument requires that the argument be a SqlParameter. To create an argument with a string name you also need to specify the type (and optionally a size):
myCommand.Parameters.Add("#managedBy", SqlDbType.NVarChar);
To set the value in one call you can use AddWithValue, wihch will infer the SQL type from the value type:
myCommand.Parameters.AddWithValue("#managedBy", comp.Rows[i][4]);

The SqlParametersCollection inside the SqlCommand object has an Add method that wants an SqlParameter object.
So your code should be something like this
myCommand.Parameters.Add(new SqlCommand("#managedBy", SqlDbType.AnsiString)).Value = .......;
There are numerous possibilities to add a new parameter to the collection, the easiest of which is
myCommand.Parameters.AddWithValue("#managedBy", comp.Rows[i][4].ToString());
This particular version however requires particular care as explained in this very detailed article on MSDN

Use the following code:
myCommand.Parameters.AddWithValue("ParameterName", anyObject);

Related

ObjectParameter: Passing Value vs Type

When should we pass a Value and when should we pass a Type to the constructor of ObjectParameter and why?
When attempting to get a SQL OUTPUT value out of a stored procedure, it does not appear to make a difference passing a value of 0,1,2 etc or typeof(long) for example.
var ob = new ObjectParameter("CustomerID", typeof(long));
// or new ObjectParameter("CustomerID", 0)
// both work
db.InsertCustomer(ob, "CustomerName");
var CustomerID = ob.Value;
It depends on the information you have available when you are calling the constructor. All 3, name, value and type, are available as properties of the object and can be set later in the code.
It is possible that you need to create the parameter object, you know the name, and type, but you may have the value at a later time. In that case you can call the ObjectParameter(String, Type) constructor.
If you have the name and value when creating the object, then ObjectParameter(String, Object) could be more useful.
var ob = new ObjectParameter("CustomerID", typeof(long));
var ob2 = new ObjectParameter("CustomerID", 0);
Shouldn't be the same as one is an int and one is a long.
In your case, where you are getting data out, it won't matter if you use a type of a value. However using a type makes it more verbose, easier to read, and easier to understand in my opinion. It can prevent any mistakes such as int vs long.

Retrieve a value from SQLParameter in C#

I am trying to retrieve a value from a List. The list is already filled but I keep getting an error saying Object reference not set to an instance of an object when I try to execute this code:
I created a global variable
private static readonly string _isDevItemParamName = "#DevItem";
In my method I call:
var devItem = sqlParams.Where(p => p.ParameterName == _isDevItemParamName).First();
This is where the error seems to occur when I do breakpoints.
Check sqlParams is null or contains any parameters and also use firstordefault instead of first because if the parameter is not available it should not through any exception.

passing a null datetime to reportparameter class?

How can I put a null value on datetime variable type?
I tried to make it nullable value, but I need to use it in ReportParameter() method to send it to my report but ReportParameter() constructor cannot take a nullable value and the ReportParameter() take just a string values!
The various constructor overloads for ReportParameter only take in a string or string array as acceptable input.
And the ReportParameter.Values property itself is actually a StringCollection in order to force the serialization to happen at compile time.
But you can pass a null value with string typing per this thread on Passing NULL parameter from aspx page to Report Server like this:
var rp = new ReportParameter("ServiceType_cd", new string[] { null });
Or per this question Report Viewer: Set null value to Report Parameters having allow null true, you can pass in a value like this:
string str = null;
var rp = new ReportParameter("ServiceType_cd", str));
you can create FailIfNull() extension method for this purpose. Please look here for more information about extension methods.

C#: Convert String to DBType.AnsiStringFixedLength

I have a stored procedure. One of its input parameters is expecting a char(8). I try to convert a string "AAA" to this particular parameter type, which is a DBType.AnsiStringFixedLength.
object v = Convert.ChangeType("AAA", param.DbType.GetTypeCode());
// param is AnsiStringFixedLength
However, all I get is an exception: Input string was not in a correct format.
And the stack trace says: at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) [...]
Why is System.Convert trying to convert a string into a number, even though the prodecure's parameter is expecting a char(8)? How do I solve this? I don't want to use one huge switch case mapping all SQL types to CLR types...
EDIT:
This is the code in question: (A generic method to call any MS SQL stored procedure)
using (SqlConnection conn = new SqlConnection(this.config.ConnectionString))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = this.config.StoredProcedureName;
conn.Open();
SqlCommandBuilder.DeriveParameters(cmd);
foreach (SqlParameter param in cmd.Parameters)
{
if (param.Direction == ParameterDirection.Input ||
param.Direction == ParameterDirection.InputOutput)
{
try
{
string rawParam = param.ParameterName.Replace("#", "");
if (this.config.Parameters.ContainsKey(rawParam))
{
try
{
param.Value = Convert.ChangeType(this.config.Parameters[rawParam],
param.DbType.GetTypeCode());
}
catch(Exception oops)
{
throw new Exception(string.Format("Could not convert to '{0}'.", param.DbType), oops);
}
}
else
throw new ArgumentException("parameter's not available");
}
catch (Exception e)
{
throw;
}
}
}
cmd.ExecuteNonQuery();
}
}
The actual parameter values are provided by this.config.Parameters - all of them are strings. I iterate through SqlCommand's parameter list and set them accordingly. Converting the string values to the parameter's Sql type is necessary here, and as far as I can see, the Sql type is provided by param.DBType.
You seem to mix up some things here, or I don't get what you try to do. The DbType (an enumeration) inherits Enum and that implements IConvertible -> You can call GetTypeCode(). But - you are now calling Enum.GetTypeCode(), which returns the underlying type. If you didn't specify it (and DbType didn't) any Enum is backed by an int.
What are you trying to solve with the code anyway? Why would you want to change the type of a string if the parameter is a string (although with a fixed length)?
Looking at the question some more it seems even more odd. You have an object v (probably for value?) - what do you care about the type?
object v1 = "Foo";
object v1 = 42;
What is the difference for you? I guess you want to pass the values to something else, but - if you only reference the value as object you might still need to cast it.
Please update your question and explain what you really want to do, what you expect to gain.
Regarding the comment:
I'm using Convert.ChangeType(object
value, TypeCode typeCode), so it's not
really converting into an Enum/int. At
least that's what I thought...
See above: DbType.GetTypeCode() is not what you want. Try it, give me the benefit of the doubt: What do you expect to get from DbType.AnsiStringFixedLength.GetTypeCode()? What is the actual result, if you try it?
Now to your code: You try to set the SqlParameter.Value property to the "correct" type. Two things: According to the documentation you probably want to set the SqlParameter.SqlValue, which is the value using SQL types according to the docs. SqlParameter.Value, on the other hand, is the value using CLR types and allows to infer both DbType and SqlValue. Sidenote, implementation detail: The SqlParameter.SqlValue setter just calls the setter of SqlParameter.Value again...
I would expect that the ADO.NET stuff converts the value on its own, if at all possible. What error are you getting without jumping through this hoops?

How to generate an instance of an unknown type at runtime?

i've got the following in C#:
string typename = "System.Int32";
string value = "4";
theses two strings should be taken to generate an object of the specified type with the specified value...
result should be:
object o = CreateUnknownType(typename, value);
...
Int32 test = (Int32)o;
Is this what are you are thinking?
object result = Convert.ChangeType("4", Type.GetType("System.Int32"));
As stated, this is too broad and can not be solved generally.
Here are some options:
Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type);
This will create an instance of the type that typename is describing. It calls the parameterless constructor of that type. (Downside: Not all objects have a parameterless constructor. Further, this does set the state of the object using value.)
Type type = Type.GetType(typename);
object o = Activator.CreateInstance(type, new[] { value });
This will create an instance of the type that typename is describing. It calls a constructor of that type that accepts one parameter of type string. (Downside: Not all objects have such a constructor. For example, Int32 does not have such a constructor so you will experience a runtime exception.)
Type type = Type.GetType(typename);
object o = Convert.ChangeType(value, type);
This will attempt to convert the string value to an instance of the required type. This can lead to InvalidCastExceptions though. For example, Convert.ChangeType("4", typeof(FileStream)) will obviously fail, as it should.
In fact, this last example (create an instance of type FileStream with its initial state determined by the string "4") shows how absurd the general problem is. There are some constructions/conversions that just can not be done.
You might want to rethink the problem you are trying to solve to avoid this morass.
Creating an instance of a type you know by name (and which should have a default constructor):
string typeName = "System.Int32";
Type type = Type.GetType(type);
object o = Activator.CreateInstance(type);
Parsing a value from a string will obviously only work for a limited set of types. You could
use Convert.ChangeType as suggested
by PhilipW
or maybe create a
Dictionary<Type,Func<string,object>>
which maps known types to known parse
functions
or use reflection to invoke the
Parse(string) method on the type,
assuming there is one:
string valueText = "4";
MethodInfo parseMethod = type.GetMethod("Parse");
object value = parseMethod.Invoke(null, new object[] { valueText });
or maybe you can use the
infrastructure provided by the .NET
component model. You can fetch the
type converter of a component and use
it like this:
TypeConverter converter = TypeDescriptor.GetConverter(type);
object value = converter.ConvertFromString(valueText);
Your logic seems a little flawed here. Obviously, if you're directly casting the object at a later time to the actual type it is, then you must know the type to begin with.
If there's something else that is missing from this question please elaborate and maybe there is a more appropriate answer than simply, "This doesn't make much sense."
Perhaps you have a set of different types, all of which implement a known interface?
For example if you have several different user controls and want to load one of them into a container, each one might implement IMyWobblyControl (a known interface) yet you might not know until runtime which of them to load, possibly from reading strings from some form of configuration file.
In that case, you'll need to use reflection to load the actual type from something like the full assembly name, then cast it into your known type to use it.
Of course, you need to make sure that your code handles invalid cast, assembly not found and any of the other exceptions that are likely to come along through something as wobbly as this...
This seems like a job for Int32.Parse(string). But to agree with the others it seems this is "unique" and one should probably think gloves.
Here's a specific example of the problem involving Azure SQL Federations...which splits data into separate db's according to a key range.
The key range types are:
SQL / .Net SQL type / CLR .Net
INT / SqlInt32 / Int32, Nullable
BIGINT / SqlInt64 / Int64, Nullable
UNIQUEIDENTIFIER / SqlGuid /Guid, Nullable
VARBINARY(n), max n 900 / SqlBytes, SqlBinary /Byte[]
Ideally, a C# function param could take either .Net SQL type or CLR .Net type but settling on just one category of type is fine.
Would an "object" type param be the way to go? And, is there a feasible way to identify the type and convert it accordingly?
The concept is something like:
public void fn(object obj, string fedName, string distName, bool filteringOn)
{
...figure out what type obj is to ensure it is one of the acceptable types...
string key = obj.toString();
return string.Format("USE FEDERATION {0} ({1}='{2}') WITH RESET, FILTERING = {3}", fedName, distName, key, (filteringOn ? "ON" : "OFF"));
}
Though the param value is cast to string, it will be recast/checked on the sql server side so validating it on the app side is desired.
After using:
Type type = Type.GetType(typename);
Try this extension method:
public static class ReflectionExtensions
{
public static T CreateInstance<T>(this Type source, params object[] objects)
where T : class
{
var cons = source.GetConstructor(objects.Select(x => x.GetType()).ToArray());
return cons == null ? null : (T)cons.Invoke(objects);
}
}
Hope this helps.

Categories