Use Rows.Find to Search DataTable for String Value - c#

I have a bit of code that I'm stuck on. I am trying to search the ReasonCodeTable for some values in the DataRow from R64CodeTable so that I can update it.
Find(_rcdr["Reason Code"]) Works fine, but Find("R64") gives me an error of Input string was not in correct format
I tried Find($"R64") and Find(#"R64"), and I even tried string testme = "R64" with Find(testme). None of it works, I continue to get the same error. "R64" is the actual string/test value I want to look for in the Column values.
foreach (DataRow _rcdr in ReasonCodeTable.Rows)
{
foreach (DataRow _dr in R64CodeTable.Rows)
{
if ( (R64CodeTable.Rows.Find(_rcdr["Reason Code"]) != null) && (R64CodeTable.Rows.Find("R64") != null) )
{
_rcdr["Desciption"] = _dr["description"];
_rcdr["Who Edited"] = _dr["editwho"];
_rcdr["Last Edit (UTC)"] = _dr["editdate"];
}
}
}

Related

Skip Records by String Matching

I'm looping through a large excel file full of Products. We want to only process rows where Brand = x, or Product = 'y'. The following code worked there was a predictable filter ie. Product1, however we are unsure what data the xsl file will hold and it could be something like "Product1 (buy me)" which wouldn't pass with this logic and the record would get ignored.
What technique can we use to match Product names with our filters? Regex, pattern matching etc. ? Or do I simply need to split the filter and loop through each? Seems like there shuold be a more elegant way.
private static bool SkipRecord(string strFilters, string key, DataRow row)
{
//include the record if it matches our filter
var strField = row[key].ToString();
bool skip = true;
if (strField != null && strField != "")
{
skip = !strFilters.ToLower().Contains(strField.ToLower());
}
return skip;
}
List<ResultRow> xlsRows = new List<ResultRow>();
foreach (DataRow row in dataTable.Rows)
{
if (SkipRecord(f.brandFlag, "Brand", row) && SkipRecord(f.productFlag, "Name", row))
continue;
}
appSettings.json
"CustomSettings": {
"BrandFlag": "Gibson|Fender|Jackson",
"ProductFlag": "Product 1|ProductTwo|Product3",
}
(One comment first, I think the first method is missing the
return skip;
line).
For the specific case you mentioned it would work if you changed the order of the "Contains" arguments:
skip = !strField.ToLower().Contains(strFilters.ToLower());

Data Binding DataGridView to ComboBox Throwing Null Value Exception

I am trying to to bind data from DataGridView in two ComboBoxes. In ComboBox one is cbosearchby and other cbosearchvalue. cbosearchby is working perfectly but when select searchvalue error being thrown. Please help me to sort out it.
Error is :
Value cannot be null.Parameter name: value
Here is my code:
private void cboSearchBy_SelectedIndexChanged(object sender, EventArgs e)
{
cboSearchValue.Items.Clear();
cboSearchValue.Text = "";
if (cboSearchBy.SelectedIndex != -1)
{
var source = new AutoCompleteStringCollection();
string[] sValues = new string[0];
foreach (DataGridViewRow dr in dataGridView1.Rows)
{
if (!cboSearchValue.Items.Contains(dr.Cells[cboSearchBy.SelectedItem.ToString()].Value))
{
cboSearchValue.Items.Add(dr.Cells[cboSearchBy.SelectedItem.ToString()].Value);
Array.Resize(ref sValues, sValues.Length + 1);
sValues[sValues.Length - 1] = Convert.ToString(dr.Cells[cboSearchBy.SelectedItem.ToString()].Value);
}
}
source.AddRange(sValues);
cboSearchValue.AutoCompleteCustomSource = source;
}
}
If the value you're passing to Contains() is null, then it'll throw an exception.
Here's what's going on internally when you call the Contains() method:
public bool Contains(object value)
{
return IndexOf(value) != -1;
}
public int IndexOf(object value)
{
if (value == null)
throw new ArgumentNullException("value");
return InnerList.IndexOf(value);
}
To fix this, you need to check for null separately:
var searchValue = dr.Cells[cboSearchBy.SelectedItem.ToString()].Value;
if (searchValue != null && !cboSearchValue.Items.Contains(searchValue))
{
...
...
The problem here could be with this statement :
cboSearchValue.Items.Clear();
This is called immediately at the entry point of your functions and this will erase all items from your drop-down. And further in your code, you are using Contains() on that same drop-down. Since the drop-down will already be empty, you wont be able to use Contains(), suffice to say that you will receive an exception there. You might want to remove that statement from there.
I dont know what exactly your logic here is, but you can try according to the above mentioned thing.
Hope this helps.

comparing datarow value with a string in if

I have an application which stores a user selected value to the value in my dataset filled datatable. I need to set another column in the table based on this comparison. But the comparison is not working. It always returns false, not entering in the if condition.
foreach (DataRow dr in dsQuestions.Tables[0].Rows)
{
if (dr["Data"] == indicater[0])
{
dr["IsSelected"] = true;
}
}
indiactor[0] is a string array and dr["data"] is also of type string but it shows a warning that it needs to a string type.
The DataRow indexer returns the field at that index as object not as string.
I would recommend to use the strongly typed Field-extension method which also supports nullables:
if (dr.Field<String>("Data") == indicater[0]){}
... and the SetField method that also support nullable types:
dr.SetField("IsSelected", true);
Update if indicater[0] is really a string[] (not a single string), how do you want to compare a string with a string[]? If you for example want to check if the array contains this data:
if (indicater[0].Contains(dr.Field<String>("Data"))){}
That would also explain why it never enters the if: because == only compares strings by equality, other types which don't have overridden the ==-operator will compare only the reference. A string is never the same reference as a string[]. But you don't get a compile time error because you can compare an object with everything else.
First of all string can't compare using == you should use equals method:
foreach (DataRow dr in dsQuestions.Tables[0].Rows)
{
if (dr["Data"].tostring().Equals(indicater[0]))
{
dr["IsSelected"] = true;
}
May be useful for you
DataRow[] result = table.Select("Id = 1");
foreach (DataRow row in result)
{
if (row[0].Equals(indicater[0]))
{
//IsSelected
row[1]=true;
Console.WriteLine("{0}", row[0]);
}
}
Try this:
foreach (DataRow dr in dsQuestions.Tables[0].Rows)
{
if (dr["Data"].ToString() == indicater[0].ToString())
{
Convert.ToBoolean(dr["IsSelected"].ToString()) = true;
}
}

iterate through particular column in a datatable

I am Working in asp.net and c#.
I have a datatable in my application with one column.I want to iterate through that column values and check those values with someother value.please tell me how to do that.I tried it with foreach but its not working.
Code:
foreach (DataRow dr in dt.Rows)
{
int code = Convert.ToInt32(dt.Rows[0]["Code"]);
if (code == pcode)
{
//do something
}
else
{ }
}
Note:
dt is my datatable with column code.I want to compare all values in column code with pcode.
int code = Convert.ToInt32(dr["Code"]);
Although you might want to check for NULL also :)
Inside your loop, access dr, instead of dt.Rows[0].
You are always accessing the first row:
dt.Rows[0]["Code"] // use dr instead of dt.Rows[0]
dt is my datatable with column code.I want to compare all values in
column code with pcode.
So am i right when i assume that you want to compare all values with one variable, if all fields equal this value, a bool variable should be true, otherwise false?
You can use Linq:
var allEqual = dt.AsEnumerable()
.All(r => r.Field<int>("Code") == pcode);
Enumerable.All determines whether all elements of a sequence satisfy a condition.
foreach (DataRow dr in dt.Rows)
{
object o = dr["Code"];
if (o != DBNull.Value) // Check for null
{
int code = Convert.ToInt32(o);
if (code == pcode)
{
//do something
}
else
{ }
}
}

List Sorting and pattern-matching

I'm trying to sort a list of telegramms to a List of Slaves.
If the PrimeAddress and the SecondaryAddress match, the telegrams belongs to the Slave.
The devices are stored in a Datatable.
I want to check if the deivce already contains the telegramm.
My first attempt looks something like this:
public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable)
{
//TODO Das ist total dirty und gar nicht clean hier...
foreach (DataRow dRow in _deviceDataTable.Rows)
{
if (dRow.ItemArray[3] is Slave)
{
foreach (MbusTelegram mb in mList)
{
int primeID = (int)dRow.ItemArray[1];
if (primeID == LoggerID)
{
Slave slv = (Slave)dRow.ItemArray[3];
foreach (MbusTelegram mbus in mList)
{
if (slv.PrimeAddress == mbus.Header.PrimeAddress && slv.SecondaryAdd == mbus.FixedDataHeader.SecondaryAddress)
{
if (slv.ListOfTelegramms == null)
{
slv.ListOfTelegramms = new List<MbusTelegram>();
}
if (!slv.ListOfTelegramms.Contains(mbus))
{
slv.ListOfTelegramms.Add(mbus);
//TODO Check if the slave already contains the telegramm, if so don't add it..
}
}
}
}
}
}
}
return _deviceDataTable;
}
Structure of the datatable:
private void IniDataTable()
{
_deviceDataTable = new DataTable("Table");
_deviceDataTable.Columns.Add("ID", typeof(int));
_deviceDataTable.Columns.Add("IDParent", typeof(int));
_deviceDataTable.Columns.Add("Name", typeof(string));
_deviceDataTable.Columns.Add("Object", typeof(object));
_deviceDataTable.Rows.Add(new object[] { 0, DBNull.Value, "Addressen", null });
//GenerateDummyDataTable();
IniDeviceTreeView();
}
This code doesn't work very well and it doesn't check if the device already contains the telegramm. Any better ideas?
There's a few things you can do to optimize your code. Firstly take all the things that doesn't change out of the inner loop. E.g. every type you use ItemArray. They are not changing for each iteration of the inner loop but with each iteration of the outer loop secondly you seem to be iterating twice over the same collection never using the variable of the outer loop (mb) so you can eleminate that loop entirely. I've done both in the code below. I've also converted the inner most loop to LINQ but that's mostly because I find it easier to read. I'm not sure the Distinct solves the TODO. I'm not sure I get the TODO at all. It might and it might not solve it you'll need to verify that
public static DataTable mdlform_NewMBUStele(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){
//TODO Das ist total dirty und gar nicht clean hier...
foreach (DataRow dRow in _deviceDataTable.Rows.Cast<DataRow>().Where(d=>d.ItemArray[3] is Slave)){
var primeID = (int) dRow.ItemArray[1];
var slv = (Slave) dRow.ItemArray[3];
if (slv.ListOfTelegramms == null){
slv.ListOfTelegramms = new List<MbusTelegram>();
}
var list = slv.ListOfTelegramms;
if (primeID == LoggerID){
var items = from m in mList
where
slv.PrimeAddress == m.Header.PrimeAddress &&
slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress && !list.Contains(m, MbusTelegramEqualityComparer.Default)
select m;
list.AddRange(items.Distinct(MbusTelegramEqualityComparer.Default));
}
}
return _deviceDataTable;
}
if you also want to LINQify it for readability you could do as below (this might perform slightly worse):
public static DataTable mdlform_NewMBUStele2(int LoggerID, List<MbusTelegram> mList, DataTable _deviceDataTable){
var pairs = from dRow in _deviceDataTable.Rows.Cast<DataRow>()
where dRow.ItemArray[3] is Slave
let primeID = (int) dRow.ItemArray[1]
let slv = (Slave) dRow.ItemArray[3]
let list = slv.ListOfTelegramms
where primeID == LoggerID
select
new{
list,
items = (from m in mList
where
slv.PrimeAddress == m.Header.PrimeAddress &&
slv.SecondaryAdd == m.FixedDataHeader.SecondaryAddress &&
!list.Contains(m, MbusTelegramEqualityComparer.Default)
select m).Distinct(MbusTelegramEqualityComparer.Default)
};
foreach (var pair in pairs){
pair.list.AddRange(pair.items);
}
return _deviceDataTable;
}
the latter exampl requires that ListOfTelegrams is initialized to an empty list instead of null
EDIT
to have value comparison use a IEqualityComparer. The below uses the timestamps only for equality. The code is updated with the usage. If the ListOfTelegrams can contain duplicates you'll need to handle this in the call to distinct as well otherwise you can leave the call to Distinct out.
public class MbusTelegramEqualityComparer : IEqualityComparer<MbusTelegram>{
public static readonly MbusTelegramEqualityComparer Default = new MbusTelegramEqualityComparer();
public bool Equals(MbusTelegram x, MbusTelegram y){
return x.TimeStamp == y.TimeStamp;
}
public int GetHashCode(MbusTelegram obj){
return obj.TimeStamp.GetHashCode();
}
}

Categories