How to make Sqlcommand accept null values - c#

I'm trying to get data in a gridview from a database to show up in text boxes upon clicking and it works fine for the rows with no null data, although since my int columns have some null values my GetInt32 methods keep returning "Data is Null. This method or property cannot be called on Null values."
Is there a simple way to fix or work around this? Do I replace GetInt32 with another method? I'd like for the data that is null to show up blank/empty in the text boxes if possible. Here's my code if you have any suggestions, thanks.
public ArrayList GetAllPersonnel(int WorkerID) {
using (var connection = new SqlConnection(connectionString)) {
connection.Open();
String query = "Select * FROM Personnel WHERE WorkerID = " + WorkerID;
using (var command = new SqlCommand(query, connection)) {
var reader = command.ExecuteReader();
var list = new ArrayList();
while (reader.Read()) {
String firstname = reader.GetString(1);
String lastname = reader.GetString(2);
String occupation = reader.GetString(3);
String deployment = reader.GetString(4);
int disasterid = reader.GetInt32(5);
String location = reader.GetString(6);
int deployedhours = reader.GetInt32(7);
int resthours = reader.GetInt32(8);
list.Add(firstname);
list.Add(lastname);
list.Add(occupation);
list.Add(deployment);
list.Add(disasterid);
list.Add(location);
list.Add(deployedhours);
list.Add(resthours);
}
connection.Close();
reader.Close();
return list;
}
}
}

You should use IsDBNull method of the SqlDataReader
int resthours = (!reader.IsDBNull(8) ? reader.GetInt32(8) : 0);
or, more directly
list.Add((!reader.IsDBNull(8) ? reader.GetInt32(8).ToString(): string.Empty));
Said that, I have noticed that you use a string concatenation to build the sql command text to retrieve records. Please do not do that. It is very dangerous and could lead to Sql Injection
String query = "Select * FROM Personnel WHERE WorkerID = #wkID";
using (var command = new SqlCommand(query, connection))
{
command.Parameters.AddWithValue("#wkID", WorkerID);
var reader = command.ExecuteReader();
....

OK, so you're effectively saying that everything you display should be a string type, which is fine, I'm just making that point because you stated you want even integers to show up as an empty string. So how about this code?
String firstname = reader.GetString(1);
String lastname = reader.GetString(2);
String occupation = reader.GetString(3);
String deployment = reader.GetString(4);
String disasterid = reader.IsDBNull(5) ? string.Empty : reader.GetString(5);
String location = reader.GetString(6);
String deployedhours = reader.IsDBNull(7) ? string.Empty : reader.GetString(7);
String resthours = reader.IsDBNull(8) ? string.Empty : reader.GetString(8);
list.Add(firstname);
list.Add(lastname);
list.Add(occupation);
list.Add(deployment);
list.Add(disasterid);
list.Add(location);
list.Add(deployedhours);
list.Add(resthours);
Now, the reason I stated that you want to leverage everything as a string is because the default value for a int is 0 and that wouldn't meet the empty text box requirement.

You have at least two ways to sort this out
Modify your sql to select either zero or whatever you think suitable in the place of null value. This will ensure that you always have an integer value in the integer column. It can be done in the following manner
select ISNULL ( ColumnName , 0 ) as ColumnName from xxx
Always fetch object from the reader and check if it is null or not. If it is null then replace it with suitable value.

Related

MVC multiple results from SQL database not working correctly

Good morning,
I have been learning MVC .NET over the weekend and I'm trying to get data from a database but the results are not displaying:
I am using the following code:
public class ListClientsController : Controller
{
private string QueryString;
private string myConnectionString;
public List<ListClients> models = new List<ListClients>();
public ActionResult Index()
{
bool iterate = true;
string iname = "";
string isurname = "";
int iIDNO = 0;
QueryString = "select FirstName, Surname, IDNumber from [iDtB].[dbo].[Clients]";
myConnectionString = "Data Source=<name>\\SQLEXPRESS01;Integrated Security=SSPI";
SqlConnection iDtBData = new SqlConnection(myConnectionString);
iDtBData.Open();
SqlCommand SQLCMD = new SqlCommand(QueryString, iDtBData);
SqlDataReader Reader = SQLCMD.ExecuteReader();
Reader.Read();
while (iterate)
{
try
{
iname = Reader["FirstName"].ToString();
isurname = Reader["Surname"].ToString();
int.TryParse(Reader["IDNumber"].ToString(), out iIDNO);
models.Add(new ListClients
{
Name = iname,
Surname = isurname,
IDNO = iIDNO
});
Reader.NextResult();
}
catch
{
iterate = false;
}
}
Reader.Close();
iDtBData.Close();
return View(models);
}
}
For some reason I get this result:
MVC Client results
Now notably, I understand that I am getting "0" for ID number due to mismatching fields, I don't understand why I can't get multiple results to display.
Thanks in advance!
You aren't actually reading all of the results returned from the query. NextResult() returns the next result set, not the next record. Replace it with Read() and you should start getting all of the results.
I'd also eliminate the Try/Catch loop as that will prevent you from seeing any errors that do occur. Plus, Read returns a true/false to let you know if it read a record or not making eliminating it easy.
while (Reader.Read())
{
try
{
iname = Reader["FirstName"].ToString();
isurname = Reader["Surname"].ToString();
int.TryParse(Reader["IDNumber"].ToString(), out iIDNO);
models.Add(new ListClients
{
Name = iname,
Surname = isurname,
IDNO = iIDNO
});
}
I'd also recommend taking a look at how to use the using statement (https://msdn.microsoft.com/en-us/library/yh598w02.aspx) to improve handling of the connection and the data reader.

C# asp.net MySQL Values return as Null

Communicating with my asp.net keeps returning a null value... I'm actually not sure why.
I've used Post Man to push information back to it to see the result excluding the use of the WPF to ensure it's my API. The only result I can return is the result I am searching for... I.E. BanID returns BanID All others return a null value.
I've Used this method for other stuff on the same API and it works fine... Somewhere I made a typo.
This is for a search box on a C# asp.net communicating with a WPF to MySQL
[HttpPost]
[Route("A3Bans/searchBan")]
public string oSearchBan(tBan ban)
{
{
tBan bans = new tBan();
string dbConnection = "datasource=127.0.0.1;port=3306;username=admin;password=123";
MySqlConnection conDataBase = new MySqlConnection(dbConnection);
MySqlCommand dbSearch;
conDataBase.Open();
MySqlDataReader dbReader;
string selectQuery = "Select * FROM a3bans.bans WHERE BanID=" + int.Parse(ban.BanID);
dbSearch = new MySqlCommand(selectQuery, conDataBase);
dbReader = dbSearch.ExecuteReader();
if (dbReader.Read())
{
tBan searchBan = new tBan();
searchBan.GuidOrIP = dbReader.GetString("GUID");
//searchBan.BanType = dbReader.GetString("BanType");
searchBan.BanReason = dbReader.GetString("Reason");
searchBan.Proof = dbReader.GetString("Proof");
bans.Equals(searchBan);
}
dbReader.Close();
return bans.GuidOrIP;
}
If BanID is PK then only one row will be returned
If there are multiple rows for one BanID, then you need to iterate dbReader
while(dbReader.Read())
{
}
Finally check your return statement.
Change
bans.Equals(searchBan);
To
bans = searchBan;

Storing SQL Select result into String Variable

I am trying to store the result from my SQL query into a string variable. This is what I have:
string strName = dt.Rows[i][name].ToString();
string selectBrandID = "SELECT [Brand_ID] FROM [myTable] WHERE [real_name] = '" + strName + "'";
using (SqlCommand sqlCmdSelectBrandID = new SqlCommand(selectBrandID, sqlConn))
{
sqlCmdSelectBrandID .Connection.Open();
using (SqlDataReader reader = sqlCmdSelectBrandID.ExecuteReader())
{
if (reader.HasRows)
{
reader.Read();
string newBrandID = reader.GetString(reader.GetOrdinal("Brand_ID"));
}
sqlCmdSelectBrandID.Connection.Close();
}
}
This currently throws the exception Unable to cast object of type 'System.Int32' to type 'System.String'. On string newBrandID =reader.GetString(reader.GetOrdinal("Brand_ID")); line.
Any advice on how to fix this?
If your Brand_ID is stored in an integer field, then you should keep it as an integer. The GetString fails because the underlying field is not a string, you could simply use the GetInt32 (see the SqlDataReader docs)
int newBrandID = reader.GetInt32(reader.GetOrdinal("Brand_ID"));
Then, if for whatever purpose you want it as a string, it is just a matter to apply the ToString() method to your integer
string brandID = newBrandID.ToString();

DataReader IndexOutofRangeException was unhandled by user code

I ran into another issue again. I was trying to get data from the database using DataReader but I got the error when i was testing my code. Can anyone help me out? The error occurred at this line:
chkAssess = readAssess[columnName].ToString();
Below is the code snippet:
public string CheckAssess(string emailAddress, string columnName)
{
string chkAssess = "";
SqlDataReader readAssess;
//readAssess = new SqlDataReader();
string MgrAssessQry = "SELECT '"+columnName+"' FROM tblAllUsers";
//MgrAssessQry += " WHERE email ='" + emailAddress + "'";
SqlCommand cmdReadAssess = new SqlCommand(MgrAssessQry, cn);
cn.Open();
readAssess = cmdReadAssess.ExecuteReader();
while(readAssess.Read())
{
// Add the rows
chkAssess = readAssess[columnName].ToString();
}
return chkAssess;
}
try to use column name without ''
select something from table
instead of
select 'something' from table
for security reasons, don't create sql queries in that way (by concatenating strings) - use #parameters instead
2. close the reader at the end
Try this:
public string CheckAssess(string emailAddress, string columnName)
{
string chkAssess = "";
SqlDataReader readAssess;
//readAssess = new SqlDataReader();
string MgrAssessQry = "SELECT #Column_Name FROM tblAllUsers";
SqlCommand cmdReadAssess = new SqlCommand(MgrAssessQry, cn);
cmdReadAssess.Parameters.AddWithValue(new SqlParameter("Column_Name", columnName));
cn.Open();
readAssess = cmdReadAssess.ExecuteReader();
while(readAssess.Read())
{
// Add the rows
chkAssess = readAssess.GetString(0);
}
return chkAssess;
}
You have got several problems here.
Check whether your readAssess has rows like below.
if(readAssess.HasRows)
If it doesn't have rows then trying
chkAssess = readAssess.GetString(0);
would throw this error, as Arrays are index-based.
So your code should be like below
if(readAssess.HasRows)
{
while(readAssess.Read())
{
chkAssess = readAssess.GetString(0);
}
}
Other problem is you need to close both the reader & the connection afterwards.
readAssess.Close();
cn.Close();
Also your code is potentially vulnerable to SQL Injection.
if (reader.HasRows)
{
while (reader.Read())
{
int result = Convert.ToInt32(reader.GetString(0));
Console.WriteLine(result);
}
}
The most important thing is check the query first by executing in SQL Server and see if any result is coming or not.
Secondly based on the type of output you are receiving cast it to that particular data type (important).Mostly everyone is saving the data in varchar so.

What's wrong with my IF statement?

I'm creating an auditting table, and I have the easy Insert and Delete auditting methods done. I'm a bit stuck on the Update method - I need to be able to get the current values in the database, the new values in the query parameters, and compare the two so I can input the old values and changed values into a table in the database.
Here is my code:
protected void SqlDataSource1_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
string[] fields = null;
string fieldsstring = null;
string fieldID = e.Command.Parameters[5].Value.ToString();
System.Security.Principal. WindowsPrincipal p = System.Threading.Thread.CurrentPrincipal as System.Security.Principal.WindowsPrincipal;
string[] namearray = p.Identity.Name.Split('\\');
string name = namearray[1];
string queryStringupdatecheck = "SELECT VAXCode, Reference, CostCentre, Department, ReportingCategory FROM NominalCode WHERE ID = #ID";
string queryString = "INSERT INTO Audit (source, action, itemID, item, userid, timestamp) VALUES (#source, #action, #itemID, #item, #userid, #timestamp)";
using (SqlConnection connection = new SqlConnection("con string = deleted for privacy"))
{
SqlCommand commandCheck = new SqlCommand(queryStringupdatecheck, connection);
commandCheck.Parameters.AddWithValue("#ID", fieldID);
connection.Open();
SqlDataReader reader = commandCheck.ExecuteReader();
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount - 1; i++)
{
if (reader[i].ToString() != e.Command.Parameters[i].Value.ToString())
{
fields[i] = e.Command.Parameters[i].Value.ToString() + "Old value: " + reader[i].ToString();
}
else
{
}
}
}
fieldsstring = String.Join(",", fields);
reader.Close();
SqlCommand command = new SqlCommand(queryString, connection);
command.Parameters.AddWithValue("#source", "Nominal");
command.Parameters.AddWithValue("#action", "Update");
command.Parameters.AddWithValue("#itemID", fieldID);
command.Parameters.AddWithValue("#item", fieldsstring);
command.Parameters.AddWithValue("#userid", name);
command.Parameters.AddWithValue("#timestamp", DateTime.Now);
try
{
command.ExecuteNonQuery();
}
catch (Exception x)
{
Response.Write(x);
}
finally
{
connection.Close();
}
}
}
The issue I'm having is that the fields[] array is ALWAYS null. Even though the VS debug window shows that the e.Command.Parameter.Value[i] and the reader[i] are different, the fields variable seems like it's never input into.
Thanks
You never set your fields[] to anything else than null, so it is null when you are trying to access it. You need to create the array before you can assign values to it. Try:
SqlDataReader reader = commandCheck.ExecuteReader();
fields = new string[reader.FieldCount]
I don't really understand what your doing here, but if your auditing, why don't you just insert every change into your audit table along with a timestamp?
Do fields = new string[reader.FieldCount] so that you have an array to assign to. You're trying to write to null[0].

Categories