Int inadverantly cast to string behind my back - c#

This was originally a problem with Crystal Reports but I tracked down the issue to a single line of code:
foreach (DataRow dr in ds.Tables["CurrentScheduleFields"].Rows)
if (dr["MY_FIELD"].ToString() == string.Empty)
dr["MY_FIELD"] = 0;
I am using an Oracle database. The field is actually a Numeric(2). We are using straight ADO.NET and no Nullable types in this case. In one case, the field in question has a value of an int and the above line of code is fine. The other case, the value of the field is DBNull.Value, and the above or something is converting the 0 to "0" ( a string).
dr is not a `DataReader foreach (DataRow dr in ds.Tables["CurrentScheduleFields"].Rows)
Does anyone know why?
My browser is not letting me click on the Add Comments, so I am adding stuff here. Why can't I do if (dr["MY_FIELD"] == DBNull.Value)
dr["MY_FIELD"] = 0;
the debugger hits that and converts to a string with a value of "0", not 0. I guess the first answer handles this, "So the problem may be that the first "MY_FIELD" is null, convincing ADO.NET that the type for that column is a string." So it's now string with DBNull.Value in it?
My browser is locked down. I can't click on anything except edit this but:
ANSWER: Handle this on the Crystal side by changing the formula to handle a string for this value and not an int. It works!

In some cases, when dealing with DataTable, I've seen it try to "guess" at the type of a column based on the value in that column in the first row in your set. So the problem may be that the first "MY_FIELD" is null, convincing ADO.NET that the type for that column is a string.
You may want to set the schema for your DataTable before you try to load it.

Related

Column does not allow DBNull.Value

I've noticed that after running the following code, I receive a 'column X does not allow DBNull.Value' error
I've been considering adding an if else statement which relates to a column being null or white space, in order to populate a NULL string field with "NULL".
As somebody brand new to development, who did not write the original code, I was curious to know if this is a solution that you would agree with or whether there is a better/simpler way to eliminate the DBNull error?
using (sqlConn)
{
sqlConn.Open();
dropUpdateCmd.ExecuteNonQuery();
createUpdateCmd.ExecuteNonQuery();
using (var bulkCopy = new SqlBulkCopy(sqlConn))
{
foreach (DataColumn col in dt.Columns)
{
bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
}
bulkCopy.BulkCopyTimeout = 600;
bulkCopy.DestinationTableName = "Destination.GenericTable";
bulkCopy.WriteToServer(dt);
}
mergeCmd.ExecuteNonQuery();
dropUpdateCmd.ExecuteNonQuery();
sqlConn.Close();
}
It is always best to put in the real data. So if it should be NULL and not some other value then you need to talk to whoever is in charge of the database to get it changed. However, I would assume that NULL is not being allowed for a reason. In either case, if you are not sure I would recommend that you talk to someone that knows how it was intended to be. If the table not allowing NULL was intended as I assume it was then we can assume that the data you are trying to insert is not supposed to contain NULL and measures should be taken to either take out the NULL values, change them or prevent them from being added the first place.

Assigning a DataTable value to a Variable

I just wrote a simple method to get some data from an SQL server and store it in a DataTable.
Specifically the value is an integer : 666
It is an int datatype on the database and I made a variable called Credits in C# which is also an integer.
The datatable shows the value 666 in the first row so it got added without any problems.
The problem happens when I try to assign Credits = dt.Rows[0] saying
the inputstring was an incorrect format
Ive tried parsing it to an int and adding .ToString() but no matter what it gives the same error.
the latest line I tried was
Credits = Convert.ToInt32(dt.Rows[0].ToString());
But still no luck. I have looked everywhere online for a solution but I cannot find the problem.
Any help would be greatly appreciated.
You are missing column name while selecting data from Data Table. You can either use column name or column index.
int Credits = Convert.ToInt32(dt.Rows[0]["columnname"].ToString());
Please make sure that value of that column value should not be null or empty.If thats the case you have to check that before assigning to int variable.
Or You can use, TryParse
int Credits = int.TryParse(dt.Rows[0]["columnname"].ToString());
You can't assign a entire row inside a variable
string Credits = Convert.ToInt32(dt.Rows[0]["columname"].ToString());

Get data from column by using column name?

I iterate a DataTable's rows using -
DataTable dt = getDataTableFromSomeWhere();
DataRow row = null;
//for loop
row = dt.Rows[i];
How do I get the value of a column of the i-th row, by using the name of the column ?
I can iterate the columns using dt.Columns[j], but thats not what I want.
Just use the indexer taking a string parameter:
object value = row["ColumnName"];
EDIT: Assuming the value has been fetched in an appropriate type, I'd normally just cast to the CLR type you want:
int someIntegerValue = (int) row["ColumnName"];
Sometimes you may need two levels of casting (one to unbox and then another to perform an actual value conversion) but it depends on what you need.
I would recommend against converting to a string representation and then parsing that, unless you've really got no alternative. Excessive string conversions not only harm performance (usually not relevant) but they lead to sloppy type choices.
string name = (string) row["ColumnName"];
or
int i = Convert.ToInt32( row["ColumnName"]);
referencing by name is tiny bit slower but way more readable.

How do I get a value from a database using Oledb, I keep getting a DBNull exception?

int weaponDamage = Convert.ToInt32(dt.Rows[randomItem][2]);
// dt= DataTable
// randomItem = randomly chooses a row from the datatable
That code throws
"InvalidCastException was unhandled, Object cannot be cast from DBNull to other types".
Yes I am using the correct column and yes the entire column has values. The odd thing is sometimes the program ran, but then next time it gives the exception again. Could the problem lie with my Data Type in the database? It is set to Number and the Field Size property to Integer
Try some mitigation:
int weaponDamage = 0;
if (dt.Rows[randomItem][2] != DBNull.Value){ // I think, I'm doing this from memory.
if (int.TryParse(dt.Rows[randomItem][2].ToString(), out weaponDamage){
// Do whatever you need.
}
}
Check that the column has a value other then NULL. Then do a safe-cast of that value into an int.
There's no reason why you should randomly be getting a value one time, and then a NULL the next to be honest. That would imply that the data in the table is changing, or you are looking at different rows of data? Not sure, but I'd add some defensive coding in there to help.
What if you print the returned value first to see if it is a numeric, a string, a random object. You should also use proper try/catch blocks to avoid unhandled exceptions.

Dataset allowing Null values even when AllowDBNull = False?

I have designed a dataset using VS2008 dataset designer. In one of the datatables, I have set "AllowDBNull" property of most of the columns to be False. However, still if I create a DataRow containing null values for these columns, this datatable accepts this row, without any error.
Am I not understanding something here? Please advice. Thank you.
Edit Mike Spross' excellent explanation however, brings forth another question. How do we check text fields if they are System.DBNull? It is surprising that DataSets are not considering a string "" as System.DBNull and throwing an exception. Or is it not?
Edit I think I have found the problem and reason. I am initializing a new row of the DataTable, before filling in the values to that row. While initializing the row, default value for string, ie, "" might be being filled in that column. I think that's it? Any ideas about this?
The short answer is:
System.DBNull.Value != null
The longer answer is:
In C#, the concept of a NULL value in SQL is represented by the Value property of the System.DBNull class. When dealing with a database, the more familiar C# null doesn't actually mean "null value."
When you set a database column to null, ADO.NET will initialize the column to whatever the default value is for that column (for example, an int column would be initialized to 0). That is, using null can actually cause a non-null value to end up in the database, and therefore you won't get an error.
If you instead set a database column to System.DBNull.Value, the column will actually be set to NULL. This is the situation that AllowDBNulls == false will prevent you from doing.
Regarding your "bonus" ;-) question: NULL (no string) and "" (empty string) are two different things. So it's perfectly reasonable to treat them differently. It's the distinction between null and DBNull that is messing things up. If nullable types had been available at the time of designing ADO.NET, things probably would be a lot easier. But before .NET 2.0, there was no way to represent e.g. a "null integer".
Are you exactly assigning NULL values or an empty string to those columns? If you don't assign any value to a column, it will default to NULL (if a DEFAULT constraint is not imposed). Else you can assign a NULL value by doing -
ds.Tables[0].Rows[0]["Col"] = null;
If you are assigning an Empty string to those columns, it's not equal to NULL.
And if you have a NULL value in a column which has been marked as NOT NULLABLE, it will throw an error -
Column 'Col1' does not allow nulls.
EDIT:
By NOT NULLABLE, I mean AllowDBNull = false.
Your code seems correct. Can you try trimming the text?
Here's the whole code -
DataTable dt = new DataTable();
DataColumn column = new DataColumn("Col1");
column.AllowDBNull = false;
dt.Columns.Add(column);
DataRow dr = dt.NewRow();
dr["Col1"] = null;
dt.Rows.Add(dr);

Categories

Resources