Replace null value with default text - c#

I know this question has been asked many times, but I have the following piece of code that I am trying to use to default null values. Can someone please help me. I tried this code but instead of giving me "NO DATA" for the null values, it doesnt display anything. Not sure where I am going wrong.
More Detail: This code does not replace null values with "NO DATA" string. What is wrong here? What do I need to change in order for it to display "NO DATA"?
protected override void Execute(NativeActivityContext context)
{
DataSet dataset = GetDataSet.Get(context);
foreach (DataTable dt in dataset.Tables)
{
foreach (DataRow row in dataset.Tables[0].Rows)
{
if (row["USER_COMMENT"] is System.DBNull)
{
ConvertNullToEmptyString(dt);
Console.WriteLine("In if");
}
else
{
Console.WriteLine("out if");
}
}
}
TransformResult.Set(context, dataset);
}
private static string ConvertNullToEmptyString(DataTable element)
{
if (element.Rows[0]["USER_COMMENT"] == DBNull.Value || element.Rows[0]["USER_COMMENT"] == null)
{
return "NO DATA";
}
else
{
return element.Rows[0]["USER_COMMENT"].ToString();
}
}

Here is what I would do
String stringtocompare;
if(String.isnullorwhitespace(stringtocompare)){
stringtocompare = "No VALUE";
}

No need of extra function there. You just have to insert the "No DATA" in the loop like below
foreach (DataRow row in dataset.Tables[0].Rows)
{
if (row["USER_COMMENT"] is System.DBNull)
{
row["USER_COMMENT"] = "NO DATA";
Console.WriteLine("In if");
}
else
{
Console.WriteLine("out if");
}
}

A couple things that might help:
You probably want to change this:
foreach (DataTable dt in dataset.Tables)
{
foreach (DataRow row in dataset.Tables[0].Rows)
{
...
to this:
foreach (DataTable dt in dataset.Tables)
{
foreach (DataRow row in dt.Rows)
{
...
Or else you will only be querying 1 table in your loop.
Also, I'd use String.IsNullOrEmpty() to interrogate the data.

If you don't need a second function to do it, try something like this:
protected override void Execute(NativeActivityContext context) {
DataSet dataset = GetDataSet.Get(context);
foreach(DataTable dt in dataset.Tables) {
foreach(DataRow row in dt.Rows) {
row["USER_COMMENT"] = String.IsNullOrEmpty(row["USER_COMMENT"].ToString()) ? "NO DATA" : row["USER_COMMENT"];
}
}
TransformResult.Set(context, dataset);
}
But, with a second function to convert, it would look something like this:
protected override void Execute(NativeActivityContext context) {
DataSet dataset = GetDataSet.Get(context);
foreach(DataTable dt in dataset.Tables) {
foreach(DataRow row in dt.Rows) {
row["USER_COMMENT"] = ConvertNullToEmptyString(row["USER_COMMENT"]);
}
}
TransformResult.Set(context, dataset);
}
private static object ConvertNullToEmptyString(object element) {
if(String.IsNullOrEmpty(element.ToString())) {
return "NO DATA";
} else {
return element;
}
}

Use empty string instead of null
if(row["USER_COMMENT"] == string.Empty)

Did you try
private static string ConvertNullToEmptyString(DataTable element)
{
if (string.IsNullOrEmpty(element.Rows[0]["USER_COMMENT"]))
{
return "NO DATA";
}
else
{
return element.Rows[0]["USER_COMMENT"].ToString();
}
}

Related

Cannot implicitly convert DateTime to Timespan

Sql Server has the variable TEST_TIME data type as Time(7)
I created the tables in C# and it automatically assigned the Timespan datatype.
Now, i'm trying to upload csv file data to the SQL database and it is giving me an error " Cannot implicitly convert DateTime to Timespan". What would be the best way to fix this?
The user first selects the CSV file:
private void button8_Click(object sender, EventArgs e)
{
try
{
using (OpenFileDialog openfiledialog1 = new OpenFileDialog()
{Filter = "Excel Workbook 97-2003|*.xls|Excel Workbook|*.xlsx|Excel Workbook|*.xlsm|Excel Workbook|*.csv|Excel Workbook|*.txt", ValidateNames = true })
{
--After some IFs--
else if (openfiledialog1.FilterIndex == 4)
{
DataTable oDataTable = null;
int RowCount = 0;
string[] ColumnNames = null;
string[] oStreamDataValues = null;
//using while loop read the stream data till end
while (!oStreamReader.EndOfStream)
{
String oStreamRowData = oStreamReader.ReadLine().Trim();
if (oStreamRowData.Length > 0)
{
oStreamDataValues = oStreamRowData.Split(',');
//Bcoz the first row contains column names, we will populate
//the column name by
//reading the first row and RowCount-0 will be true only once
if (RowCount == 0)
{
RowCount = 1;
ColumnNames = oStreamRowData.Split(',');
oDataTable = new DataTable();
//using foreach looping through all the column names
foreach (string csvcolumn in ColumnNames)
{
DataColumn oDataColumn = new DataColumn(csvcolumn.ToUpper(), typeof(string));
//setting the default value of empty.string to newly created column
oDataColumn.DefaultValue = string.Empty;
//adding the newly created column to the table
oDataTable.Columns.Add(oDataColumn);
}
}
else
{
//creates a new DataRow with the same schema as of the oDataTable
DataRow oDataRow = oDataTable.NewRow();
//using foreach looping through all the column names
for (int i = 0; i < ColumnNames.Length; i++)
{
oDataRow[ColumnNames[i]] = oStreamDataValues[i] == null ? string.Empty : oStreamDataValues[i].ToString();
}
//adding the newly created row with data to the oDataTable
oDataTable.Rows.Add(oDataRow);
}
}
}
result.Tables.Add(oDataTable);
//close the oStreamReader object
oStreamReader.Close();
//release all the resources used by the oStreamReader object
oStreamReader.Dispose();
dataGridView5.DataSource = result.Tables[oDataTable.TableName];
}
Here is the Code:
private void button9_Click(object sender, EventArgs e)
{
try
{
DataClasses1DataContext conn = new DataClasses1DataContext();
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToDateTime(dr[3]),
**TEST_TIME = Convert.ToDateTime((dr[4])),**
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}
else
{
MessageBox.Show("I guess table is not coded yet");
}
}
EDIT
The TEST_TIME represents HH:MM:SS
The Typed Data Set is defined as:
public virtual int Update(
byte EX_ID,
byte DOC_ID,
byte PATIENT_NO,
System.DateTime TEST_DATE,
System.TimeSpan TEST_TIME)
Based on your input that dr[4] represents time values in hours:minutes:seconds format I recommend following solution.
private TimeSpan GetTimeSpan(string timeString)
{
var timeValues = timeString.Split(new char[] { ':' });
//Assuming that timeValues array will have 3 elements.
var timeSpan = new TimeSpan(Convert.ToInt32(timeValues[0]), Convert.ToInt32(timeValues[1]), Convert.ToInt32(timeValues[2]));
return timeSpan;
}
Use above method as following.
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToDateTime(dr[3]),
**TEST_TIME = GetTimeSpan(dr[4].ToString()),**
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}
This should give your the value you want. You will face runtime issues if value of dr[4] is not in hours:minutes:seconds format. That I will leave it up to you.
First of all Timespan and DateTime are 2 differents type without implicit conversion available. Since Timespan is a time value between two DateTime, you need to know your referenced time (DateTime) used to start the mesure of your Timespan.
For example it could be from DateTime dtReferential = new DateTime(1900, 01, 01);
In order to give a SQL Timespan value you need to give it a C# Timespan! Change TEST_TIME value to a Timespan. And finally, give it the substracted value of your referenced time.
Using the previous example:
else if (textBox3.Text.Contains("GEN_EX"))
{
foreach (DataTable dt in result.Tables)
{
foreach (DataRow dr in dt.Rows)
{
GEN_EX addtable = new GEN_EX()
{
EX_ID = Convert.ToByte(dr[0]),
DOC_ID = Convert.ToByte(dr[1]),
PATIENT_NO = Convert.ToByte(dr[2]),
TEST_DATE = Convert.ToTimespan(dr[3]),
TEST_TIME = dtReferential.Subtract(Convert.ToDateTime(dr[4]))
};
conn.GEN_EXs.InsertOnSubmit(addtable);
}
}
conn.SubmitChanges();
MessageBox.Show("File uploaded successfully");
}

08P01: insufficient data left in message for Nullable DateTime

I have database table having one column defined as timestamp without time zone. Now from my c# application, when I try to insert null value in that column using NpgSql BeginBinaryImport it gives error message as mentioned below:
08P01: insufficient data left in message
Below is the code which I am trying to execute:
static void Main(string[] args)
{
BulkInsert();
}
private static void BulkInsert()
{
DataTable table = new DataTable();
table.Columns.Add("firstname", typeof(String));
table.Columns.Add("lastname", typeof(String));
table.Columns.Add("logdatetime", typeof(DateTime));
table.Columns.Add("status", typeof(int));
table.Columns.Add("id", typeof(long));
var dataRow = table.NewRow();
dataRow["firstname"] = "MyFirstName";
dataRow["lastname"] = "MyLastName";
dataRow["logdatetime"] = DBNull.Value;
dataRow["status"] = 1;
dataRow["id"] = 10;
table.Rows.Add(dataRow);
var data = new DataAccess();
using (var npgsqlConn = new NpgsqlConnection([ConnectionString]))
{
npgsqlConn.Open();
var commandFormat = string.Format(CultureInfo.InvariantCulture, "COPY {0} {1} FROM STDIN BINARY", "logging.testtable", "(firstName,LastName,logdatetime,status,id)");
using (var writer = npgsqlConn.BeginBinaryImport(commandFormat))
{
foreach (DataRow item in dataTable.Rows)
{
writer.StartRow();
foreach (var item1 in item.ItemArray)
{
writer.Write(item1);
}
}
}
npgsqlConn.Close();
}
The issue is the DBNull.Value you're trying to write - Npgsql doesn't support writing nulls this way. To write a null you need to use the WriteNull() method instead.
I can make Npgsql accept DBNull.Value, but only for the overload of Write() which also accepts an NpgsqlDbType (because Npgsql has to write the data type, and with DBNull.Value we have no idea what that is).
EDIT: Have done this, see https://github.com/npgsql/npgsql/issues/1122.
I faced same issue while bulk copying data in table. To solve this I have created an extension method so you dont have to null check on all fields
public static void WriteWithNullCheck(this NpgsqlBinaryImporter writer, string value)
{
if (string.IsNullOrEmpty(value))
{
writer.WriteNull();
}
else
{
writer.Write(value);
}
}
this can be made generic by
public static void WriteWithNullCheck<T>(this NpgsqlBinaryImporter writer, T value,NpgsqlDbType type)
{
if (value == null)
{
writer.WriteNull();
}
else
{
writer.Write(value, type);
}
}

How can I delete all child rows and the parents in a DataSet?

So, I have a DataRelation as is shown below:
Oraciones1 = new DataRelation("Antecedentes",
dsPubs.Tables["Consecuente"].Columns["Id"],
dsPubs.Tables["Antecedentes"].Columns["Id"]);
dsPubs.Relations.Add(Oraciones1);
where dsPubs is dsPubs = new DataSet() and that DataSet has two tables which Both have a data relation. Then; I am iterating over the parents to get the childs, just to get some task done as is shown next:
foreach (DataRow rowAuthor in dsPubs.Tables["Consecuente"].Rows) {
foreach (DataRow rowTitle in rowAuthor.GetChildRows(Oraciones1)) {
}
}
and what I want to do is to remove all the child and the parent from an a specified value which is passed through a function(i.e).
public void function(string value ){
foreach (DataRow rowAuthor in dsPubs.Tables["Consecuente"].Rows){
foreach (DataRow rowTitle in rowAuthor.GetChildRows(Oraciones1){
if(value==rowTitle["id_d"].ToString()){
//remove all the child and the parent from the specified variable "value"
}
}
}
}
I tried to get it done by using rowTitle.Delete() and rowAuthor.Delete() method but it seemed to not be working, because I think it removes the whole table, and a the time The foreach wanted to continue to grab another value from the table "Consecuente" it crashed.
Thank you a lot!!
var innerRows = new List<DataRow>();
var outerRows = new List<DataRow>();
foreach (DataRow rowAuthor in dsPubs.Tables["Consecuente"].Rows)
{
foreach (DataRow rowTitle in rowAuthor.GetChildRows(Oraciones1))
{
if (value == rowTitle["id_d"].ToString())
{
//remove all the child and the parent from the specified variable "value"
innerRows.Add(rowTitle);
outerRows.Add(rowAuthor);
}
}
}
foreach(DataRow row in innerRows)
{
row.Delete();
}
foreach (DataRow row in outerRows)
{
row.Delete();
}

c# datagridview red cross

I have a datagridview and datatable. I use the datatable as a datasource of the datagridview. I add and update the data using threads as below. And if I am done with the data I remove it. But two times there were big red x in front of the datagridview. I couldn't find out why? Below are my sample.
Note: This does not always occur, I got this error only two times but I need to handle! Thanks in advance.
Thread listData;
DataTable dt = new DataTable();
Form1_load()
{
dataGridview.DataSource = dt;
}
public void ListData()
{
foreach(var item in data)
{
if(item.delete)
{
var row = dt.Rows.Find(item.id);
if(row != null) { row.Delete();}
continue;
}
listData = new Thread(delegate() { InsertOrUpdateData(item.Id); });
listData.Start(); listData.Join();
}
}
public void InserOrUpdateData(int id)
{
// Here I retrieve some data from database
// and insert or update to the datatable
// like dt.Rows.Add(fields) and dt.Rows.Find(id)["fieldName"] = "new Value"
}
You need to use Invoke method
if (gridView.InvokeRequired)
gridView.Invoke(new MethodInvoker(() => gridView.DataSource = YOUR_DATASOURCE));
else
gridView.DataSource = YOUR_DATASOURCE;

return empty List in catch block

I have a c# function that reads file locations from a Datatable, and returns a List with all the file lcoations to the calling method.
In the Catch block, I want to return an empty list with a false so teh calling method can cancel it's operation.
But I can't get my return statement to compile.
Would it be better to pass in a list as a refernce, and have the function return a boolean true/false?
here is the code I am trying:
public static List<string> getEmailAttachments(string emailID, System.Data.DataTable emails)
{
List<string> allAttachments;
//System.Data.DataTable oTbl = new DataTable();
try
{
System.Diagnostics.Debugger.Break();
var results = from myRow in emails.AsEnumerable()
where myRow.Field<string>("itemID") == emailID
select myRow;
System.Diagnostics.Debug.Print("attachments");
foreach (DataRow myRow in results)
{
System.Diagnostics.Debug.Print(myRow.Field<string>("attachmentsPath"));
allAttachments.Add(myRow.Field<string>("attachmentsPath"));
//DataTable dt = (DataTable)myRow["attachmentsPath"];
//DataTable oTbl = dt.Clone();
//DataRow[] orderRows = dt.Select("CustomerID = 2");
//foreach (DataRow dr in orderRows)
//{
// oTbl.ImportRow(dr);
//}
// myTable.ImportRow(dr);
//oTbl.Rows.Add(myRow);
//oTbl.ImportRow(myRow);
}
return allAttachments;
}
catch (Exception ex)
{
logBuilder("common.getEmailAttachments", "Exception", "", ex.Message, "");
return new List<string>emptyList(); // cannot compile
}
}
If someone still looking...
Use IEnumerable<string> as return type and:
return Enumerable.Empty<string>();
Change this line:
return new List<string>emptyList(); // cannot compile
to:
return new List<string>();
Passing a list as a refernce, and returning a boolean value from the function, it is a bad idea. Your method called getEmailAttachments, it's load attachments, and it should return attachments. If you want to check the result of loading attachments, i can suggest you return null and check the returned value.
Use
return new List<string>();
I would take a slightly different approach.
I would return an empty list but ALSO set the initial capacity to ZERO!
Like this:
return new List<string>(0);//notice the initial capacity to zero.
The reason is for memory consumption and optimization... I know it is a micro optimization but it won't hurt anything. It might actually benefit the overall application.
A better way has been added since around .Net Framework 4.6 and in the Core .Net versions,
return Array.Empty<T>();
This allocates a single array (which is an IList) and reuses it for all subsequent requests for an empty array of that type. Its fast, and clean.
try this..
public static List<string> getEmailAttachments(string emailID, System.Data.DataTable emails)
{
List<string> allAttachments;
//System.Data.DataTable oTbl = new DataTable();
try
{
System.Diagnostics.Debugger.Break();
var results = from myRow in emails.AsEnumerable()
where myRow.Field<string>("itemID") == emailID
select myRow;
System.Diagnostics.Debug.Print("attachments");
foreach (DataRow myRow in results)
{
System.Diagnostics.Debug.Print(myRow.Field<string>("attachmentsPath"));
allAttachments.Add(myRow.Field<string>("attachmentsPath"));
//DataTable dt = (DataTable)myRow["attachmentsPath"];
//DataTable oTbl = dt.Clone();
//DataRow[] orderRows = dt.Select("CustomerID = 2");
//foreach (DataRow dr in orderRows)
//{
// oTbl.ImportRow(dr);
//}
// myTable.ImportRow(dr);
//oTbl.Rows.Add(myRow);
//oTbl.ImportRow(myRow);
}
//return allAttachments;
}
catch (Exception ex)
{
logBuilder("common.getEmailAttachments", "Exception", "", ex.Message, "");
allAttachments= new List<string>();
}
return allAttachments;
}
what about
allAttachments.Clear();
return allAttachments;

Categories