Let us assume we have an open SqlConnection and execute an arbitrary query resulting in a table consisting of one column Foo which contains integers.
To read those integers I noticed two kinds of possibilities to access the values in the column:
using (var reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
// access value directly either by column name or index
int i = (int)reader["Foo"];
int j = (int)reader[0];
// access value by using GetOrdinal
int k = reader.GetInt32(reader.GetOrdinal("Foo"));
}
}
}
Both approaches result in the same values of course. I am using the first approach as it seems easier to me to use the column name to access the value directly instead of using it to get its index and then using that index to access the value.
But I am quite new to the subject so what are the best practices here? Current conventions? Differences in matters of performance?
All are correct way but reader["Foo"] and reader[0] are using the overloaded indexers defined. It's always easy/readable and recommended to use the column name in the indexer instead of using the index though. Not sure about any performance differences between them.
int i = (int)reader["Foo"];
int j = (int)reader[0];
using reflector you can see the indexer [] internally is the same as calling the methods
public override object this[int i]
{
get
{
return this.GetValue(i);
}
}
public override object this[string name]
{
get
{
return this.GetValue(this.GetOrdinal(name));
}
}
so the actual difference is. if you know the position and care about performance use the int version of the methods.
int j = (int)reader[0];//direct array access for some column
int j = reader.GetInt32(0);
if you don't know the position or prefer readability use the string version
//must first goto hash table and waist time looking for column index
int j = (int)reader["price"]; //but at least we know the meaning of the column
int j = reader.GetInt32(reader.GetOrdinal("price"));
int j = (int)reader.GetValue(reader.GetOrdinal("price"));
and to finalize the difference bettween GetInt32 and GetValue is just that GetInt32 does the type validation and cast for you, so if you know the type of data makes you life easier..
PS. the performance hit of looking up the index of the column by name is usually ignorable.. but.. is not to be dismissed, I have a project where GetOrdinal that is one of the most called functions hundreds of thousand of times, summing up to seconds of time, that I could have avoided by using ints, and now that I'm hitting bottlenecks, I can't rewrite the application.
Something like that:
using (var reader = command.ExecuteReader()) {
// if (reader.HasRows) is redundant
// do not repeat this in the loop
int k_index = reader.GetOrdinal("Foo");
while (reader.Read()) {
// reader["Foo"] is not necessary int;
// better practice is to convert since reader["Foo"] could be, say, Oracle Number
int i = Convert.ToInt32(reader["Foo"]);
// usually, reader[123] (instead of reader["MyField"]) syntax looks ugly, but
// it may happen that, say, "id" is always the first field in the query -
// so reader[0] syntax is reasonable
int j = Convert.ToInt32(reader[0]);
// what if reader[index] is declared as Int64 but contains Int32 values - convert
int k = Convert.ToInt32(reader[k_index]);
}
}
You will use SqlDataReader a lot so keep it more simple as possible, specifying column name:
int i = (int)reader["Foo"];
Related
I have a DataTable (i.e. DT) that has a few columns of Type of String (i.e. colStr1, colStr2), and a few of the Type of Int32 (i.e. colInt1, colInt2). This is set in the DB as well as in the DataTable created in the code.
For one of my functions, I need to get a Sum of the Int column. But for specific data, the Sum will exceed the Int32.MaxValue.
What I'm looking for are two options:
(not sure this one is possible) Add a row, that will contain the SUM of the column while changing the Type for the SUM cell/field from Int32 to Int64.
Add a copy of those Int32 columns (with all the values) to the same DT, but a new column is defined as Type of Int64 (and data converted accordingly). Then I can do a SUM for those.
I have following code for this, but not sure if it is most elegant and best way to do it:
DataColumn colBal64 = new DataColumn();
colBal64.ColumnName = "BalanceInt64";
colBal64.DataType = typeof(Int64);
dt.Columns.Add(colBal64);
for (int i = 0; i <= dt.Rows.Count - 1; i++)
{
DataRow dr = dt.Rows[i];
dr["BalanceInt64"] = dr["BalanceInt32"];
}
Any suggestion on how to better approach this? And the best way to do it?
So far I found only copying the whole DT into a new DT, and not Column within the same DT, while converting into another Type.
Your first approach is, indeed, not possible. Given you have two Int32 columns, you could have an Int64, then split that bit-wise across the two Int32s, but that seems like a lot of hassle if you don't need to store the sum. (If you do need to store the sum, a better approach would be to use another table, or something else depending on how exactly you need to store that summation.)
Depending on how exactly you're writing this summation function, you should be able to just sum your values into an Int64, either by casting (as below) if you're using a .Sum() call or by just having your aggregation variable being an Int64 and adding the Int32s to it. As an example, the following works just fine in C#:
using System;
using System.Data;
var bigNumTable = new DataTable();
var column = new DataColumn();
column.DataType = System.Type.GetType("System.Int32");
column.ColumnName = "the_number";
bigNumTable.Columns.Add(column);
for (int i=0; i<32; i++)
{
var row = bigNumTable.NewRow();
row["the_number"] = Int32.MaxValue;
bigNumTable.Rows.Add(row);
}
try
{
Console.Write($"Summing as Int32: {bigNumTable.AsEnumerable().Sum(row => row.Field<Int32>("the_number"))}");
}
catch (OverflowException)
{
Console.WriteLine("Summing as Int32 resulted in an OverflowException");
}
Console.Write($"Summing after casting to an Int64: {bigNumTable.AsEnumerable().Sum(row => (Int64)row.Field<Int32>("the_number"))}");
Which prints the following to the console:
Summing as Int32 resulted in an OverflowException
Summing after casting to an Int64: 68719476704
If you need to do the summation in another language, you should be able to cast the Int32s to Int64s if necessary, but if you'd even need that depends on the context of the function you're writing.
I have a simple form that accepts a number from a radio button selection (1-5) of 11 questions and posts the values into a database as varchar(10) data. I intend to send the user to a result page that lists the sum of these scores through a simple for loop, but when I try parsing the data to integer format, it simply results in zero due to error parsing. Here's an example of my code:
// Q1 - Q11 are the questions in my Db, using Model property
int sum = 0;
int temp = 0;
String question;
for (int i = 11; i >= 1; i--)
{
question = "Model.Q" + i.ToString();
temp = int.Parse(question);
sum += temp;
}
return sum;
What's strange is that if I parse them individually, such as writing:
Int32.TryParse(Model.Q5, out temp);
I am able to parse the data just fine. My console shows that the loop keeps the question variable as "Model.Qx" with quotations, ultimately resulting in 0 for the sum. I have also tried using Int32.TryParse(); for that as well and it resulted in no difference, besides handling the error.
Can a string simply not be parsed if it contains punctuation in concatenation with the i variable, or am I missing something else here? I want to avoid parsing each question individually, as it looks rather ugly in code.
Thanks in advance.
You problem is that you're trying to access a variable by using a string with the same name. This won't work, in the same way that the name gitgecko is not you.
If your model has got a number of properties with similar names, you could write a function to switch between them:
object GetQ(int number)
{
switch(number)
{
case 1: return Model.Q1;
case 2: return Model.Q2;
// etc...
}
}
Or you could change your model to store these variables in an array or list, or whatever is appropriate.
For example, if you've currently got:
class Model
{
string Q1;
string Q2:
// repeated 11 times
You could have:
class Model
{
string[] Q = new string[11];
}
which gives you the ability to do Model.Q[x]
I have the attached code which trys to find all 1s in an array input by the user.
The program asks the user to select the array size, then input a number of that size with some 1s in it. It then counts the number of 1s found.
I guess that the input the user gives is in the form of a string? So, if they input 12345 it would be a string with one 1 in it.
I am trying to convert the array to int32, though I don't think I fully understand why it has to be int32 either.
If somebody could help me understand this programs' workings and why I'm getting the following error I'd be thankful.
An unhandled exception of type 'System.FormatException' occurred in
mscorlib.dll Additional information: Input string was not in a correct
format.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace count1s
{
class Program
{
static void Main(string[] args)
{
int count = 0;
Console.WriteLine("Enter a number for the array length");
int limit = int.Parse(Console.ReadLine());
int[] array1s = new int[limit];
Console.WriteLine("Enter a number with some 1s in it");
for(int i=0; i<limit; i++)
{
array1s[i] = Convert.ToInt32(Console.ReadLine());
}
foreach (int number in array1s)
{
if (number == 1)
{
count++;
}
}
Console.WriteLine("The number of 1s in the array is: {0}", count);
Console.ReadLine();
}
}
}
You are getting this error because you are entering the array elements in one line.
If you enter one element on one line then program will work fine.
If you want to accept numbers on one line then you can use split function like
String []numbers = Console.ReadLine().Split(' ');
for (int i = 0; i < limit; i++)
{
array1s[i] = Convert.ToInt32(numbers[i]);
}
foreach (int number in array1s)
{
if (number == 1)
{
count++;
}
}
I don't think I fully understand why it has to be int32 either.
It doesn't have to be. That depends on your input. If the user enters a number small enough, it can also fit into a short (which is 16 bits), and you can parse the string into that.
why I'm getting the following error
Because you're trying to parse a string which isn't parse-able to a valid int value. If you're not sure the input is valid, you can use a method such as int.TryParse, which returns a boolean indicating the success or failure of the parsing:
int i = 0;
while (i < limit)
{
string value = Console.ReadLine();
int parsedValue;
if (!int.TryParse(value, out parsedValue))
{
Console.WriteLine("You've entered an invalid number. Please try again");
continue;
}
array[i] = parsedValue;
i++;
}
If you want to count all occurrences of 1, you can simply use Enumerable.Count which takes a predicate:
return array.Count(number => number == 1);
Use this as
for(int i=0; i<limit; i++)
{
int value;
var isNumber = int.TryParse(Console.ReadLine(), out value);
if(isNumber)
{
array1s[i] = value;
}
else
{
Console.WriteLine("Invalid value you have entered");
continue;
}
}
Well, now I feel like a bit of an idiot.
I tried some of your responses, thanks very much for that, and they are good. I went back and tried the code I originally posted as well and found that it does work. I just need to hit carriage return after each entry into the array.
I'll take a look at all of this properly later to find out what is going on.
Thanks again all - gotta say - was really surprised to get so many responses on here so quickly. Awesome!!
I just found a really good article on the Microsoft: DEV204x Programming with C# course I have started online. I think this will be helpful to all who follow with the same questions I had. Hopefully I'm not breaking any copyright laws or stackoverflow rules. It's a free course, so I doubt it.
Data Conversions
C# supports two inherent types of conversion (casting) for data types, implicit and explicit. C# will use implicit conversion where it can, mostly in the case when a conversion will not result in a loss of data or when the conversion is possible with a compatible data type. The following is an example of an implicit data conversion.
Converting from smaller to larger integral types:
int myInt = 2147483647;
long myLong= myInt;
The long type has a 64-bit size in memory while the int type uses 32-bits. Therefore, the long can easily accomodate any value stored in the int type. Going from a long to an int may result in data loss however and you should use explicit casting for that.
Explicit casts are accomplished in one of two ways as demonstrated with the following coe sample.
double myDouble = 1234.6;
int myInt;
// Cast double to int by placing the type modifier ahead of the type to be converted
// in parentheses
myInt = (int)myDouble;
The second option is to use the methods provided in the .NET Framework.
double myDouble = 1234.6;
int myInt;
// Cast double to int by using the Convert class and the ToInt32() method.
// This converts the double value to a 32-bit signed integer
myInt = Convert.ToInt32(myDouble);
You will find many other methods in the Convert class that cast to different integral data types such as ToBoolean(), ToByte(), ToChar(), etc.
The Convert.ToInt32() method can also be used to cast a string literal to a numeric data type. For example, you may have GUI-based application in which uses input data into text boxes. These values are string values when passed to the code in your application. Use of the above method to cast the string to numbers can help prevent exceptions in your code when trying to use the wrong data type in a specific area.
C# also provides another mechanism to deal with casting types. The use of the TryParse() method and Parse() methods can help with casting as well. These methods are attached to the types in C# rather than the Convert class. An example will help demonstrate.
// TryParse() example
bool result = Int32.TryParse(value, out number);
// Parse() example
int number = Int32.Parse(value);
In the TryParse() example, the method returns a Boolean result indicating if the conversion succeeded. In the Parse() example, if the conversion does not succeed, an exception will be thrown.
I use C# and ASP.NET.
I use this code pasted below in my application with no problems, but I would like to know if there is a better way to achieve the same result.
What I need to do:
I need set a variable int imageId using a Loop.
Variable imageId it is outside the Loop so can be used in other part of my code.
My questions:
Why if I use just int imageId; the compiler complain (ERROR: Use of unassigned local variable 'imageId' )?
I use a nullable int type instead of an int imageId = 0; so I can set it on a null value .. (to me seems semantically correct) would you recommend that? If no why.
What is you favorite approach to this kind of problem?
Thanks guys for your support!!!!
int? imageId = null;
foreach (DictionaryEntry valueEntry in e.Keys)
{
if (valueEntry.Key.Equals("ImageContentId"))
{
imageId = Convert.ToInt32(valueEntry.Value.ToString());
break;
}
}
Please give me a sample of your code thank!
You could use the IOrderedDictionary method Contains. This would allow you to drop the loop construct altogether. e.g.
if( e.Keys.Contains("ImageContentId") )
{
imageId = Convert.ToInt32( e.Keys["ImageContentId"].ToString() );
}
Also if you know that the Value is a string you might be interested in the Int32.TryParse method e.g.
int imageId ;
if( Int32.TryParse(e["ImageContentId"].ToString(), out imageId ) )
{ }
The only reason that you would want to use an int? is if the data you're manipulating could be uninitialised. If you're parsing data and it's garbage you have 2 options:
(NB: This assumes that you don't want to be throwing Exceptions RE the bad data).
1) Use a default value - This has the benefit of being inherently tolerant of bad data.
2) Use the int? construct - This has the advantage of informing the rest of the code that the data in known to be bad and ensures that they are designed to cope with null values.
As for which is better... that can only be answered within the constructs of the system. If you're performing interop with external dll's that don't support nullable types then the decision is pretty clear!
As for the compiler error: if you're initializing imageId within an if statement there will be occasions where the initialization branch won't be taken e.g. a bad value. To ensure that imageId is always initialized, the compiler will force you to initialize it outside of a conditional code path. Generally I always try and initialize a variable when I declare it. e.g.
int imageId = 0;
Answers for your Questions
All value type in .net are implemented as structure. And all structure must be initialized before usage.
If you are interested in checking if that value exists or not then nullable is a correct choice. Else no issues with int imageId = 0
You can use below code
int imageId = 0;
if( e.Contains("ImageContentId") )
{
//If you are sure value is int
imageId = (int)e["ImageContentId"];
}
you could use Linq to find the entry:
var foundKey = e.Keys.FirstOrDefault(k => k.Key.Equals('ImageContentId'));
Then the ternary expression to get the value:
int? imageId = foundKey == null ? (int?)null : Convert.ToInt32(foundKey.Value);
However, what type is the Value? If you're sure it's an int, you can cast it, rather than calling Convert.ToInt32. Also, Convert.ToInt32 returns 0 for some cases where you might want (int?)null.
My favorite approach to this kind of problem is not to rely on overloading the value-holding variable with information regarding whether a value was found. I do this explicitly.
bool value_present = false;
int imageId;
foreach (DictionaryEntry valueEntry in e.Keys)
{
if (valueEntry.Key.Equals("ImageContentId"))
{
value_present = true;
imageId = Convert.ToInt32(valueEntry.Value.ToString());
break;
}
}
And then test value_present before using imageId.
That said, and as others have noted, this is crazy.
Don't loop like this, just call e.Keys.Contains()
Don't convert to a string and then back to an int. If it's an int, cast it.
I'm writing a class to store some kind of a table-structure.
Now each column in this table structure has a name, and an index.
Now each row in this column will be looped through, and the data will 90% of the cases be requested using the name of the column rather then the index of it.
So what's a good data structure to store the columns, so that it can retrieve the index very quickly based upon the name. Right now I'm using a simple string[], but I wonder if there are faster ways to do this.
Parts of the code:
private string[] _columns;
private int _width;
private int getIndex(string columnName)
{
for (int i = 0; i < _width; i++)
{
if (_columns[i] == columnName) return i;
}
return -1;
}
The names of the columns will be constant after they've been set, and they're mostly about 10-16 characters long.
Thanks in advance.
Since you are usually going to access columns by the name, this sounds like a good place to use a Map (Dictionary class in C#) that maps Strings to Columns (String arrays). That would allow O(1) access for the name rather than the current O(n) in the above code.
The disadvantage is that you wouldn't be able to access directly by column index anymore. However, this is simple to solve--just keep your list of column names and use those to index! You can then call
_columnsMap[_columns[index]]
if you ever need to index by number, and it is still O(1) time.
Use a Dictionary<string,int> to store the names of the columns against their ID.
Using your example (which misses how _columns is populated):
private IDictionary<string,int> _columns;
private int _width;
private int getIndex(string columnName)
{
return _columns[columnName];
}