DataReader is null or empty - c#

Using C#
I have a datareader that return a lsit of records from a mysql database.
I am trying to write code that checks if the datareader isnull. The logic behind this is: If the datareader having field then display the info otherwise hide the field.
I have tried:
cmd1 = new OdbcCommand("Select * from tb_car where vehicleno = '" + textbox2.text + "';", dbcon);
dr1 = cmd1.ExecuteReader();
if (dr1["tb_car"]. != DBNull.Value)
{
textbox1.Text = "contains data";
}
else
{
textbox1.Text = "is null";
}
The above code gives me this error:
Exception Details: System.IndexOutOfRangeException: Additional
Any help would be greatly appreciated...

I see a few problems here... First, it looks like you're trying to access the table name in the line:
if(dr1["tb_car"] != DBNull.Value
You should be passing a FIELD NAME instead of the table name. So if the table named "tb_car" had a field called CarId, you would want to have your code look like:
if(dr1["CarId"] != DBNull.Value)
If I'm right, then there is probably no field named "tb_car", and the Index is Out of Range error is because the DataReader is looking for an item in the column collection named "tb_car" and not finding it. That's pretty much what the error means.
Second, before you can even check it , you have to call the DataReader's Read() command first to read a line from the database.
so really your code should look like...
while(dr.Read())
{
if(dr1["CarId"] != DBNull.Value)
{
....
and so on.
See here for the proper use of a DataReader: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.read.aspx
Finally, if you're just checking to see if there are any rows in the table, you can ignore all of the above and use the HasRows property as in
if(dr.HasRows)
{
....
although if you're using the while(dr.Read()) syntax, the code in the while loop will only execute if there are rows in the first place, so the HasRows could potentially be unnecessary if you don't want to do anything with no results. You would still want to use it if you want to return a message like "no results found", of course..
Edit - Added
I think there's a problem also with the line
if(dr1["CarId"] != DBNull.Value)
You should be using if DataReader's IsDbNull() method. as in
if(dr.IsDbNull("CarId"))
Sorry I missed that the first time around.

Use dr1.Read() to check that there is a row before attempting to read values. Read gets the first row initially, and then returns subsequent rows, returning true if row available or empty/end of set.
eg.
// for reading one row
if (rd1.Read())
{
// do something with first row
}
// for reading thru multiple rows
while (rd1.Read())
{
// do something with current row
}

Related

Checking for Empty Cells in Google Sheets using c# via Google Sheets API v4

This is code snippet. I have successfully connected to Google Sheets API v4 using C#. I found out that when a cell is blank or empty. I get this error: System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index'
As you can see Input ID in cell E3 cell is blank/empty. I tried this in the code below to check once it is blank it gives value of zero, but still gives same error. What I want to achieve is once a cell is blank I give it value of zero or unknown?? Bear in mind if I put value in cell E3 code works fine, Just need to check for empty cells. Reference from here https://developers.google.com/sheets/api/quickstart/dotnet#further_reading
int inputId = 0;
foreach (var row in values)
{
SqlCommand command = new SqlCommand();
command.Connection = ServerConnection; // <== lacking
command.CommandType = CommandType.Text;
command.CommandText = "INSERT into [GoogleSheetsAPI].[dbo].[Followup Stage] ( [Timestamp], [Email Address], [Do You Want To Follow Up] ,[Is The Issue Resolved From Follow Up] ,[Input ID]) VALUES (#TimeStamp, #EmailAddress, #DoYouWantToFollowUp, #IsTheIssueResolvedFromFollowUp, #InputID ) ";
command.Parameters.AddWithValue("#TimeStamp", Convert.ToDateTime(row[0]));
command.Parameters.AddWithValue("#EmailAddress", Convert.ToString(row[1]));
command.Parameters.AddWithValue("#DoYouWantToFollowUp", Convert.ToString(row[2]));
command.Parameters.AddWithValue("#IsTheIssueResolvedFromFollowUp", Convert.ToString(row[3]));
//checking for null or if the cell is empty still doesn't work this way??
if (row[4] == null || string.IsNullOrEmpty(Convert.ToString(row[4])))
{
inputId = 0;
}
else
{
inputId = Convert.ToInt32(row[4]);
}
command.Parameters.AddWithValue("#InputID", inputId);
try
{
// ServerConnection.Open();
int recordsAffected = command.ExecuteNonQuery();
}
catch (SqlException E)
{
// error here
Console.Write(E.Message);
// Console.ReadLine;
}
}
One thing we have to understand is that Sheets API doesn't read "empty cells",. You can read that in Read a single range grouped by column:
Empty trailing rows and columns are omitted from the response.
It may not be direct but that's what also the tests says. When I read an empty cell, I get the same error
Uncaught TypeError: Cannot read property 'length' of undefined
One workaround to this would be to write a placeholder for "empty cells" like what you did with "zero or unknown".
If that's not an option, you can also do an if-else like method to catch the error before it halts your program. To implement this, do something like:
example:
for (i = 0; i < range.values.length; i++) {
//IF NOT AN EMPTY CELL
if(range.values[i][j]){
console.log(range.values[i][i] + " is my value");
//IF IT's AN EMPTY CELL
}else{
console.log("U N D E F I N E D");
//your method to write to that cell
writeToSheet();
}
}
Hopefully this simple analogy helps you.

SqlBulkCopy - The given ColumnName does not match up with any column in the source or destination

I'm trying to use SqlBulkCopy to copy data into an SQL database table however it is (wrongly) saying that the columns don't match. They do match. If I use a breakpoint to see the names of the columns being mapped, they're correct. The error message shows the name of the column, and it is correct.
This is my method. I have an identical method that does work and the only difference is where it gets the column names from. The strings containing the column names, however, are EXACTLY identical.
public static bool ManualMapImport(DataTable dataTable, string table)
{
if(dataTable != null)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlBulkCopy import = new SqlBulkCopy(connection);
import.DestinationTableName = "[" + table + "]";
foreach (string s in Global.SelectedColumns)
{
/* The s string variable here is the EXACT same as
the c.ToString() in the other method below */
if (ColumnExists(table, s))
import.ColumnMappings.Add(s, s);
else
return false;
}
connection.Open();
import.WriteToServer(dataTable); //Error happens on this line
connection.Close();
return true;
}
else
{
return false;
}
}
This is the almost identical, working method:
public static bool AutoMapImport(DataTable dataTable, string table)
{
if (dataTable != null)
{
SqlConnection connection = new SqlConnection(connectionString);
SqlBulkCopy import = new SqlBulkCopy(connection);
import.DestinationTableName = "[" + table + "]";
foreach (DataColumn c in dataTable.Columns)
{
if (ColumnExists(table, c.ToString()))
import.ColumnMappings.Add(c.ToString(), c.ToString());
else
return false;
}
connection.Open();
import.WriteToServer(dataTable);
connection.Close();
return true;
}
else
{
return false;
}
}
If it helps, the column names are: ACT_Code, ACT_Paid, ACT_Name, ACT_Terminal_Code, ACT_TCustom1, ACT_TCustom2. These are exactly the same in the database itself. I'm aware that SqlBulkCopy mappings are case sensitive, and the column names are indeed correct.
This is the error message:
An unhandled exception of type 'System.InvalidOperationException'
occurred in System.Data.dll
Additional information: The given ColumnName 'ACT_Code' does not match
up with any column in data source.
Hopefully I'm just missing something obvious here, but I am well and truly lost.
Many thanks.
EDIT: For anyone happening to have the same problem as me, here's how
I fixed it.
Instead of having the ManualMapImport() method be a near-clone of
AutoMapImport(), I had it loop through the columns of the datatable
and change the names, then called AutoMapImport() with the amended
datatable, eliminating the need to try and map with plain strings at
all.
According to MSDN (here), the DataColumn.ToString() method returns "The Expression value, if the property is set; otherwise, the ColumnName property.".
I've always found the ToString() method to be wonky anyway (can change based on current state/conditions), so I'd recommend using the ColumnName property instead, as that's what you are actually trying to get out of ToString().
OK, failing that, then I'd have to guess that this is a problem with case-sensitivity in the names of the columns in the source datatable, as SQLBulkCopy is very case-sensitive even if the SQL DB is not. To address this, I would say that when you check to see if that column exists, then you should return/use the actual string from the datatable's column list itself, rather than using whatever string was passed in. This should be able to fix up any case or accent differences that your ColumnsExist routine might be ignoring.
I had the same problem... The message might seem a bit misleading, as it suggests you didn't perform the correct mapping.
To find the root of the problem I have decided to go step by step in adding table columns and calling the WriteToServer method.
Assuming you have a valid column mapping, you will have to ensure the following between the source DataTable and the destination table:
The column types and lengths (!) do match
You have provided a valid value for each non-empty (NOT NULL) destination column
If you don't control your identity column values and would like the SQL Server do this job for you, please make sure not to specify the SqlBulkCopyOptions.KeepIdentity option. In this case you don't add the identity column to your source either.
This should be all for your bulk insert to work. Hope it helps.

SQL Case statement generating error in Visual studio report

Hi I am currently working with a report in Visual Studio 2008. I use the query below to create a data set. This works correctly in SQL / SMSS and in the dataset when I test the query.
SELECT
CASE WHEN Make LIKE 'FO%' THEN 'Ford'
WHEN Make LIKE 'HON%' THEN 'Honda'
END Make,
CASE WHEN model LIKE 'CIV%' THEN 'Civic'
WHEN model LIKE '%AC%' THEN 'Accord'
ELSE model
END model,
year, AVG(Fuel.MPG) as AVGMPG
From cars, Fuel
Where Fuel.ID=cars.ID
AND year > 2003
AND Make is not NULL
AND model is not NULL
AND year is not NULL
Group by Make, model, year
When I have a report reference the dataset it generates the following error;
An error has occurred during report processing. Exception has been
thrown by the target of an invocation. Failed to enable constraints.
One or more rows contain values violating non-null, unique, or
foreign-key constraints.
Since the actual SQL statement is larger and involves several CASE statements, all of which work, I have narrowed it down to the else portion of the statement.
For background, I am trying to pull all the data from model but group certain values that are similar, but still pull the rest of the data as well.
My best guess here is that for some rows, the model column contains null, while the data set in your report does not allow null for the column value.
SELECT
CASE WHEN Make LIKE 'FO%' THEN 'Ford'
WHEN Make LIKE 'HON%' THEN 'Honda'
END Make
With no default case, you'll end up with an error. Change it to
SELECT
CASE WHEN Make LIKE 'FO%' THEN 'Ford'
WHEN Make LIKE 'HON%' THEN 'Honda'
ELSE ''
END Make
Here's a quick way to find the column in error and the actual error:
var ds = new DataSet();
ds.EnforceConstraints = false;
/* Fill dataset */
try {
ds.EnforceConstraints = true;
} catch {
foreach (DataTable tbl in ds.Tables) {
if (tbl.HasErrors) {
foreach (DataRow row in tbl.GetErrors()) {
foreach (DataColumn col in row.GetColumnsInError() {
row.GetColumnError(col);
}
}
}
}
}

How to check empty DataTable

I have a DataSet where I need to find out how many rows has been changed using the following code:
dataTable1 = dataSet1.Tables["FooTable"].GetChanges();
foreach (DataRow dr in dataTable1)
{
// ...
}
DataSet has DataSet.HasRow but DataTable doesn't have such method. If there is no changed rows. changedDT1 will be a null value, causing the loop to throw exception.
How do I check if DataTable is empty? I tried Rows.Count - doesn't work...
First make sure that DataTable is not null and than check for the row count
if(dt!=null)
{
if(dt.Rows.Count>0)
{
//do your code
}
}
If dataTable1 is null, it is not an empty datatable.
Simply wrap your foreach in an if-statement that checks if dataTable1 is null.
Make sure that your foreach counts over DataTable1.Rows or you will get a compilation error.
if (dataTable1 != null)
{
foreach (DataRow dr in dataTable1.Rows)
{
// ...
}
}
Normally when querying a database with SQL and then fill a data-table with its results, it will never be a null Data table. You have the column headers filled with column information even if you returned 0 records.When one tried to process a data table with 0 records but with column information it will throw exception.To check the datatable before processing one could check like this.
if (DetailTable != null && DetailTable.Rows.Count>0)
Don't use rows.Count. That's asking for how many rows exist. If there are many, it will take some time to count them. All you really want to know is "is there at least one?" You don't care if there are 10 or 1000 or a billion. You just want to know if there is at least one. If I give you a box and ask you if there are any marbles in it, will you dump the box on the table and start counting? Of course not. Using LINQ, you might think that this would work:
bool hasRows = dataTable1.Rows.Any()
But unfortunately, DataRowCollection does not implement IEnumerable.
So instead, try this:
bool hasRows = dataTable1.Rows.GetEnumerator().MoveNext()
You will of course need to check if the dataTable1 is null first. if it's not, this will tell you if there are any rows without enumerating the whole lot.
You can also simply write
if (dt.Rows.Count == 0)
{
//DataTable does not contain records
}
This is an old question, but because this might help a lot of c# coders out there, there is an easy way to solve this right now as follows:
if ((dataTableName?.Rows?.Count ?? 0) > 0)
As from MSDN for GetChanges
A filtered copy of the DataTable that can have actions performed on it, and later be merged back in the DataTable using Merge. If no rows of the desired DataRowState are found, the method returns Nothing (null).
dataTable1 is null so just check before you iterate over it.
Sub Check_DT_ForNull()
Debug.Print WS_FE.ListObjects.Item(1).DataBodyRange.Item(1).Value
If Not WS_FE.ListObjects.Item(1).DataBodyRange.Item(1).Value = "" Then
Debug.Print WS_FE.ListObjects.Item(1).DataBodyRange.Rows.Count
End If
End Sub
This checks the first row value in the DataBodyRange for Null and Count the total rows
This worked for me as I downloaded my datatable from server It had not data's but table was created with blanks and Rows.Count was not 0 but blank rows.
bool empty = !DataTableExtensions.AsEnumerable(DataTableToCheck).Any()

how to populate textboxes with values of datareader

i have some textboxes. in first textbox i entered a vaue like empid. after the clicking a button which goes to database and checks for the columns specified by me.
i get that data in datareader.
from datareader i need to display the particular employ information in the remaining textboxes.
how can i achieve this.
Assuming your datareader is called rdr, something like this would work:
while(rdr.Read())
{
txtBox1.Text = rdr.Item["DBFieldName1"].ToString();
txtBox2.Text = rdr.Item["DBFieldName2"].ToString();
}
while (dr.Read())
{
string checkValue = dr.GetValue(0).ToString();
if (checkValue == myEmpIdTextbox.Text)
{
Texbox2.Text = dr.GetValue(1).ToString();
Texbox3.Text = dr.GetValue(2).ToString();
}
}
Works in C# - Visual Studio 2015.
The values in the brackets () next to GetValue indicate the column number, relative to your SQL Select query.
EXAMPLE:
SELECT coloumn1, coloumn2, coloumn3 FROM table
Then, in this case, Textbox3.Text will be made equal to the data in coloumn3, and Textbox2. Text to coloumn2, for that row where coloumn1 is equal to your value in your Empid textbox.

Categories

Resources