This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I'm trying to update multiple rows in a data grid, the code gets the job done but I still seem to get a
Object reference not set to an instance of an object
When I check the records the desired status updates accordingly for the selected records within the gridview.
private void UpdateWorkerStatus()
{
SqlCommand cmdUpdate = new SqlCommand(#"UPDATE Workers2
SET WorkerStatus = #WorkerStatus
WHERE FullName = #FullName", cn);
cmdUpdate.Parameters.AddWithValue("#WorkerStatus", SqlDbType.VarChar).Value = txtWorkerStatus.Text;
cmdUpdate.Parameters.AddWithValue("#FullName", SqlDbType.VarChar).Value = txtFullName.Text;
foreach (DataGridViewRow row in grdWorkers.Rows)
{
cmdUpdate.Parameters["#WorkerStatus"].Value = row.Cells["WorkerStatus"].Value.ToString();
cmdUpdate.Parameters["#FullName"].Value = row.Cells["FullName"].Value.ToString();
cmdUpdate.ExecuteNonQuery();
}
}
thank you in advance! :)
private void UpdateWorkerStatus()
{
SqlCommand cmdUpdate = new SqlCommand(#"UPDATE Workers2
SET WorkerStatus = #WorkerStatus
WHERE FullName = #FullName", cn);
cmdUpdate.Parameters.AddWithValue("#WorkerStatus", SqlDbType.VarChar).Value = txtWorkerStatus.Text;
cmdUpdate.Parameters.AddWithValue("#FullName", SqlDbType.VarChar).Value = txtFullName.Text;
foreach (DataGridViewRow row in grdWorkers.Rows)
{
cmdUpdate.Parameters["#WorkerStatus"].Value = row.Cells["WorkerStatus"].Value!=DBNull.Value? row.Cells["WorkerStatus"].Value.ToString():"";
cmdUpdate.Parameters["#FullName"].Value = row.Cells["FullName"].Value!= DBNull.Value ? row.Cells["FullName"].Value.ToString():"";
cmdUpdate.ExecuteNonQuery();
}
}
Since you don't supply us with the information of where the exception is thrown, I'm going to assume it's on one of the .ToString() calls as those are the most likely. Probably one of the values for WorkerStatus or FullName are null, resulting in the exception when you call the .ToString() method.
I would check the values for null before calling the .ToString(). This enables you to fill the parameter values with something meaningful if the value you are trying to read is null:
if (row.Cells["WorkerStatus"].Value != null)
cmdUpdate.Parameters["#WorkerStatus"].Value = row.Cells["WorkerStatus"].Value.ToString();
else
cmdUpdate.Parameters["#WorkerStatus"].Value = string.Empty // or some meaningful default value of your chosing
You can reduce this statement to one line using this:
cmdUpdate.Parameters["#WorkerStatus"].Value = (row.Cells["WorkerStatus"].Value != null) ? row.Cells["WorkerStatus"].Value.ToString() : string.Empty;
And of course you should do the same for FullName.
Try this,Instead of .ToString() use Convert.Tostring( row.Cells["FullName"].Value)
Same for "WorkStatus"
Related
What I'm trying to do is retrieve the FullName values where the Username corresponds to the user, which does indeed work, the problem is I don't exactly know how to store the values when there is more than one value, I tried using an array but when there is for example two values, when retrieving it, characterReader[0] will be null and characterReader[1] will have only the first retrieved value, however if there is only 1 value to be retrieve characterReader[0] will no longer be null and display the correct value.
This is my code, I'm not exactly sure this is even the right way:
SqlCommand displayCharactersCMD = new SqlCommand(String.Format("SELECT FullName FROM [Characters] WHERE Username='{0}'", username), con);
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
int counter = 0;
while (reader.Read())
{
if (counter != countCharsToVar)
{
characterReader = new string[countCharsToVar];
characterReader[counter] = reader[0].ToString();
counter++;
}
else
break;
}
}
Example when there are two values to be retrieved:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will become null.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will contain the first value.
How I intend it to work:
API.consoleOutput("CHAR 1: " + characterReader[0]); - This will display first value.
API.consoleOutput("CHAR 2: " + characterReader[1]); - This will display second value.
Instead of storing values in array, you can utilize List<>. This might help you:
SqlCommand displayCharactersCMD = new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName");
displayCharactersCMD.Parameters.AddWithValue("#checkPlayerName", username);
var characterReader = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
characterReader.Add(reader[0].ToString());
}
}
Here's a really good link from Microsoft: https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/retrieving-data-using-a-datareader
Use the GetString(columnNumber) method to get the whole value from the row. That should make it easy for you.
Hope this helps.
You need to iterate SqlDataReader for each value, calling reader.Read() makes the reader to point to the next row, when it reaches the end and there is no more rows in the resultset it returns false.
When a "read" is done, the reader is moved to point to the next row so you can access all the columns in this way. reader[0] will be the first column, reader[1] for the second column and so on, in your example you only have one column fullname.
You can add all your results to a list in this way:
var values = new List<string>();
using (SqlDataReader reader = displayCharactersCMD.ExecuteReader())
{
while (reader.Read())
{
values.Add(reader[0]);
}
}
Note: as #steve points, parameter does not work that way, you remove the string.format call and use the name of the parameter.
new SqlCommand("SELECT FullName FROM [Characters] WHERE Username=#checkPlayerName"), con);
This question already has answers here:
Object cannot be cast from DBNull to other types
(8 answers)
Closed 7 years ago.
I have a simple Employee Database which allows me to add new a employee, with some of my textbox fields left empty (I'm using winform). It currently works ok in the database. It registers NULL values in place of the empty textboxes. My problem now is how to display all the employees from the database in a gridview:
When I run the program, it pops up a messagebox saying "object cannot be cast from DBNull to other types". Is it because 'age' and 'married' columns in my database contain some null values? Please help, I'm trying to understand how to use nullable types in c# with mssql database.
public static List<Employee> GetEmployees()
{
List<Employee> empListToReturn = new List<Employee>();
SqlConnection conn = GetConnection();
string queryStatment = "SELECT * FROM Employee";
SqlCommand sqlCmd = new SqlCommand(queryStatment, conn);
try
{
conn.Open();
SqlDataReader reader = sqlCmd.ExecuteReader();
while (reader.Read())
{
Employee emp = new Employee();
emp.FirstName = reader["firstname"].ToString();
emp.LastName = reader["lastname"].ToString();
emp.Age = Convert.ToInt32(reader["age"]);
emp.Married = (reader["married"]);
empListToReturn.Add(emp);
}
reader.Close();
}
catch (SqlException ex)
{
throw ex;
}
finally
{
conn.Close();
}
return empListToReturn;
}
As the error states, you can't convert null to other types. Specifically in this case an int:
emp.Age = Convert.ToInt32(reader["age"]);
(Since value types can't be null.)
Simply check for null before converting:
if (reader["age"] == DBNull.Value)
emp.Age = 0;
else
emp.Age = Convert.ToInt32(reader["age"]);
Edit: As pointed out in a comment, there are multiple ways to do this. Some may be more efficient than others. For example:
if (reader.IsDBNull(reader.GetOrdinal("age")))
emp.Age = 0;
else
emp.Age = reader.GetInt32(reader.GetOrdinal("age")));
Unless the performance difference is significant, I'd probably prefer the former when using named columns instead of the ordinal, since this requires an extra method call to get the ordinal. (Unless there's a string overload that I'm just not seeing on MSDN?)
Additionally, if you don't want 0 as an option, you might change the .Age property from int to Nullable<int> (or int? for short). This would allow you to set a null value on that object:
if (reader.IsDBNull(reader.GetOrdinal("age")))
emp.Age = null; // <-- here
else
emp.Age = reader.GetInt32(reader.GetOrdinal("age")));
This is often very useful when there's a clear semantic difference between 0 (which is a valid value) and null (which is a lack of a value).
It's also worth noting that this code is bad practice:
catch (SqlException ex)
{
throw ex;
}
Not only is your catch block not actually handling the exception at all, it's actually overwriting the stack trace. Which would make debugging more difficult. Since the catch block isn't doing anything, just remove it entirely. You don't need a catch in a try/finally.
I have a database named testDB, which contains table Versions, which contains a column [Release Date] with datetime format.
Now, I want to read it in my C# Windows Service:
protected void SqlConnect()
{
SqlCommand comSql;
DateTime relDate;
SqlDataReader myReader = null;
using (SqlConnection myConnection = new SqlConnection(_server +
_username +
_password +
"Trusted_Connection=yes;" +
"database=testDB; " +
"connection timeout=30"))
{
try
{
myConnection.Open();
comSql = new SqlCommand("select [Release Date] from dbo.Version",
myConnection);
myReader = comSql.ExecuteReader();
while (myReader.Read())
{
//Here's my problem, explained below
}
}
catch
{
}
finally
{
if (myReader != null) myReader.Close();
}
}
}
Now, I want to assign the value stored in that column to relDate variable. However
relDate = myReader.GetDateTime();
requires GetDateTime to have column number passed there (if I understand this right). But I already selected column in my comSql. Is this the correct way to deal with this problem, ie. just putting the column number in the code?
EDIT: Ok judging by the answers I might word this question wrong or something.
I know that I must pass the column index to GetDateTime(). I ask if there's a way to do that without hardcoding it like GetDateTime(0).
You can use GetOrdinal method on the data reader to get ordinal of the column from its string name. In that way, you won't have to hardcode the column index.
GetOrdinal is also useful when you're reading data from the data reader in a loop. You can initialize the index variable before the loop starts and then use it in every iteration of the loop.
This question already has answers here:
How to safely cast nullable result from sqlreader to int?
(9 answers)
Closed 8 years ago.
Hi I'm currently using the following to get the columns of a sql server database
public IDataReader myReader()
{
DbCommand = new SqlCommand("Select * from Mydatabase");
SqlConnection con = new SqlConnection(connectionstr);
con.Open();
DbCommand.Connection = con
return command.ExecuteReader(CommandBehavior.closeConnection);
}
IDataReader reader = myReader();
while (reader.Read())
{
int? a = (int?)reader["myIntColumn"];
}
At other locations (for other tables) the code works fine and also for this table it works fine until I come to the fields that are int in the database.
Then I get System.InvalidCastException (in other tables I didn't get that problem).
Is there anything I did wrong? Or that I have to do to make this work?
(the int value in question is NULL in the DB)
Your code will not work when the result is null, since the value of the column will be DbNull.Value on the .NET side then.
Try this:
int? a = reader["myIntColumn"] as int?;
You need to explicitly check for DBNull.Value as follows:
while (reader.Read())
{
var a = reader["myIntColumn"] == DBNull.Value ? null : (int?)reader["myIntColumn"];
}
I have the following query:
public static string GetCustomerName(string customerNo)
{
string query = "query to get customer";
var myConn= new MYConnection();
using (SqlConnection con = new SqlConnection(myConn.MYConnectionString))
{
con.Open();
SqlCommand cmd = new SqlCommand(query, con);
cmd.Parameters.Add("#customerNo", SqlDbType.NVarChar).Value = customerNo;
object result = cmd.ExecuteScalar();
return result == DBNull.Value ? String.Empty : (string)result;
}
}
I'm calling the method above like this:
string customerName = GetCustomerName(CustomerID);
if (customerName.Contains(Constants.Company.CompanyName))
{
Additional Logic...
}
However, I'm getting a Object Reference Null error if my method doesn't return a customer name. I would think that the GetCustomer method would return an empty string.
If I change the call to get the CustomerName to below, it works perfectly.
string customerName = GetCustomerName(emailAndSTCodeInfo.CustomerID);
if (String.IsNullOrEmpty(customerName))
{
customerName = "";
}
if (customerName.Contains(Constants.Chase.ACCOUNT_NAME))
{
Additional Logic
}
So, my question is, what would be the proper way of handling this if my GetCustomer method doesn't find a record and returns null. I'm currently using the working code above but it seems like a hack or something.
Any help would be greatly appreciated.
ExecuteScalar returns null if no record is returned.
To guarantee that GetCustomerName never returns null, you could change the last line to
return Convert.ToString(result);
Convert.ToString(object) returns an empty string if the argument is either null or DBNull.Value.
If a query returns no rows, then executing it with ExecuteScalar will return null, not DBNull.Value.
So your GetCustomerName method needs to check for a null return value as well as DBNull.Value.