I want to query a specific value from a DataTable.
Lets say i have a DataTable which contains 2 columns:
id
item_name
Now what I want to do is like i would do it with mysql: SELECT * FROM "DataTable" WHERE item_name = 'MyItemName'
And then get the id that belongs to that 'item_name'...
int blah;
while (MyReader.Read())
{
blah = MyReader.GetInt32("id");
}
Now: how can I do this using DataTable?
I've got a snippet but I can't seem to show the returned value in a messagebox:
string test = Item1txt.Text;
var query = producten.Rows.Cast<DataRow>().Where(x => x.Field<string>("item_name") == test);
foreach (var st in query)
{
MessageBox.Show(st.ToString());
// how can i show the id that belongs to "test" ?
}
query will be an IQueryable<DataRow>, so st will be a DataRow. Try this:
foreach (var st in query)
{
MessageBox.Show(st.Field<int>("id").ToString());
}
Or if you know there will only item with that item_name, here's an alternative version which does essentially the same thing, but is probably a bit easier to understand:
var st = producten.Rows.Cast<DataRow>().FirstOrDefault(x => x.Field<string>("item_name") == test);
if(item != null)
{
MessageBox.Show(st.Field<int>("id").ToString());
}
You can use linq directly on the datatable without the need of Rows or the Cast.
var query = producten.AsEnumerable().Where(x => x.Field<string>("item_name") == test);
foreach (var st in query)
{
MessageBox.Show(st.Field<int>("id"));
}
I usually use the Rowfilter property of the defaultview of the datatable, but I must admit I never did LINQ myself, so there's probably a better way now...
Related
I'm using SQL and I have a table shown below in my DB.
Id Remark1 Remark2 Remark3 Remark4
------------------------------------------------
1 AAA BBB CCC DDD
2 EEE FFF GGG HHH
How can I get all the values from Remark* columns as IEnumerable<string> using the following DTO?
class MyDTO
{
public int ID { get; }
public IEnumerable<string> Remarks { get; }
}
NOTE: I'm using SqlKata (Dapper), which you can also use when answering.
If you're using Dapper, maybe just use the non-generic Query API. This returns each row as dynamic, but this can also be cast to IDictionary<string,object>, which allows you to access each named column (for example, via foreach).
foreach (IDictionary<string, object> row in conn.Query(sql, args))
{
var obj = new MyDto();
var vals = new List<string>();
obj.Remarks = list;
foreach ((var key, var value) in row)
{
if (key == nameof(obj.Id))
obj.Id = (int)value;
else
vals.Add((string)value);
}
// do something with obj
}
```
Another option would be to create an ugly looking - but working - UNION ALL query:
SELECT Id, Remark1 as Remark FROM Table
UNION ALL
SELECT Id, Remark2 as Remark FROM Table
UNION ALL
SELECT Id, Remark... as Remark FROM Table
That's can be done in a for..loop using SqlKata, calling the Union inside the loop
https://sqlkata.com/docs/combine#union-except-intersect
Non-Tested code sample:
var q = new Query("Table").Select("Id", "Remark1 as Remark");
for(int r=2;r<=50;i++)
{
var u = new Query("Table").Select("Id", $"Remark{r} as Remark");
q = q.Union(u);
}
I have a DataTable with some attributes data get from a database, each data in that DataTable belong to a product, and each product could have more than one attribute.
So i have another DataTable which has all the products in a foreach by looping through each row i'm adding each product to it's List<Plu> like this:
var productAttr = new List<Plu.Attributi>();
foreach (DataRow rowPlu in dt.Rows)
{
try
{
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
productAttr,
null,
(int)rowPlu["ID_MENU_PRP"]
));
}
catch
{
return plu;
}
}
For now the productAttr is empty but now i need to add to each product it's attributes, so with the following function i get a DataTable filled with data from database with all product attributes:
var attributi = Attributi(connection, idNegozio);
and then i was trying to do something like this inside the foreach
foreach (DataRow rowPlu in dt.Rows)
{
try
{
int id = (int)rowPlu["ID_PLUREP"];
plu.Add(new Plu(
id,
(string)rowPlu["CODICE_PRP"],
(string)rowPlu[ESTESA],
(string)rowPlu[DESCR], (float)rowPlu["PRE_PRP"],
rowPlu.IsNull("IMG_IMG") ? null : (string)rowPlu["IMG_IMG"],
from row in attributi.AsEnumerable() where row.Field<int>("ID_PLUREP_VAT") == id select row,
null,
(int)rowPlu["ID_MENU_PRP"]
));
}
catch
{
return plu;
}
}
But the LINQ returns a EnumerableRowCollection while i need a IEnumerable<Plu.Attribute>, so i was wondering if there is a lazy way to cast the .AsEnumerable to IEnumerable<Plu.Attrbute>...
The problem is, that the DataTable only knows which values are in the cells. It does not know what these values stand for. It does not know that the number in column 0 is in fact an Id. It doesn't know that the string in column 1 is the Name of a Customer, and the DateTime in column 2 is the Birthday of the Customer.
If you will be using the contents of this Datatable (or similar DataTables) for other queries in the future, you need some translation from DataRow to the items that they stand for.
Once you've got the translation from DataRow to Plu, you can convert your DataTable to an IEnumerable<Plu>, and do other LINQ processing on it.
Usage will be like:
DataTable table = ...
var mySelectedData = table.AsEnumerable().ToPlus()
.Where(plu => ...)
.Select(plu => new {...})
.ToList();
You need two extension methods: one that converts a DataRow to a Plu and one that converts a sequence of DataRows to a sequence of Plus. See extension methods demystified
public static Plu ToPlu(this DataRow row)
{
// TODO implement
}
public static IEnumerable<Plu> ToPlus(this IEnumerable<DataRow> dataRows)
{
// TODO: exception if null dataRows
return dataRows.Select(row => row.ToPlu());
}
If desired, create an extension method from DataTable to extract the Plus:
public static IEnumerable<Plu> ExtractPlus(this DataTable table)
{
// TODO: exception if table null
return table.AsEnumerable().ToPlus();
}
Usage:
DataTable table = ...
IEnumerable<Plu> plus = table.ExtractPlus();
I haven't got the faintest idea what a Plu is, and you forgot to mention the relevant properties of the Plu, so I'll give you an example of a table that contains Customers:
class Customer
{
public int Id {get; set;} // Id will be in column 0
public string Name {get; set;} // Name will be in column 1
...
}
public static Customer ToCustomer(this DataRow row)
{
return new Customer
{
Id = (int)row[0],
Name = (string)row[1],
};
}
If desired, instead of columnIndex you can use the name of the column.
So by only creating a ToPlu, and a one-liner method to convert sequences of DataRows to a sequence of Plus, you've extended LINQ with your methods to read your tables.
To be on the safe side, consider creating an extension method that converts a sequence of Plus to a DataTable. This way, the layout of the table is in one location: ToPlu(DataRow) and ToDataRow(Plu). Future changes in the table layout will be easier to manage, users of your DataTable will only think in sequences of Plus.
You can do something like below. If you want IEnumerable<Plu> you can remove the .ToList() from the end.
dt.AsEnumerable().Select(x => new Plu {
Id = x.Field<int>("ID_PLUREP"),
CodicePrep = x.Field<string>("CODICE_PRP"),
....
Attributes = attributi.AsEnumerable()
.Where(y => y.Field<int>("ID_PLUREP_VAT") == x.Field<int>("ID_PLUREP"))
.Select(z => new Attributi
{
....
}).ToList(),
....
}).ToList();
I have a datatable in memory and I need to select some records from it, walk through the records making changes to fields and they same the changes back to the datatable. I can do this with filters, views, and sql but I'm trying to do it in Linq.
var results = (from rows in dtTheRows.AsEnumerable()
select new
{
rows.Job,
}).Distinct();
foreach (var row in results)
{
firstRow = true;
thisOnHand = 0;
var here = from thisRow in dtTheRows.AsEnumerable()
orderby thisRow.PromisedDate
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
foreach(var theRow in here)
{
// business logic here ...
theRow.OnHandQuantity = 5;
} // foreach ...
The first linq query and foreach are gain the list of subsets of data to be considered. I include it here in case it is relevant. My problem is at this line:
heRow.OnHandQuantity = 5;
My error is:
"Error 19 Property or indexer 'AnonymousType#1.OnHandQuantity' cannot be assigned to -- it is read only"
What am I missing here? Can I update this query back into the original datatable?
var here = from thisRow in dtTheRows.AsEnumerable()
orderby thisRow.PromisedDate
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
Instead of passing three variables in select, pass thisRow itself. That may solve error on statement - theRow.OnHandQuantity = 5;
The error is self descriptive, you can't update/modify an anonymous type. You have to return the original entity you want to modify from your query.
select thisRow;
instead of
select new
{
thisRow.OnHandQuantity,
thisRow.Balance,
thisRow.RemainingQuantity
};
I am trying to find a fast way to find a string in a Column in a DataTable and add it to a comboBox, and this is the code i tried so far :
adapter = new SqlDataAdapter("Select Id_Editeur ID,Libelle_Editeur Editeur from Editeur", myClass.cnx);
adapter.Fill(myClass.ds, "Editeur");
foreach (String str in myClass.ds.Tables["Editeur"].Columns[1].ToString())
editeurBox.Properties.Items.Add(str);
and that's doesn't work it gives me this error :
foreach statement cannot operate on variables of type
'System.Data.DataColumn' because 'System.Data.DataColumn' does not
contain a public definition for 'GetEnumerator'
How can I do that ? (I don't want the for loop solution).
foreach (var row in myClass.ds.Tables["Editeur"].AsEnumerable())
{
editeurBox.Properties.Items.Add(row[1].ToString());
}
or Full linq-style:
editeurBox.Properties.Items.AddRange(
myClass.ds.Tables["Editeur"]
.AsEnumerable()
.Select(dr => dr[1].ToString()
);
You can try with this code - based on LINQ Field operator
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<string>("RowNo") == "yourSearch"
select myRow;
I think you need to loop through the rows and grab the column that you want. Your code is trying to loop through the column collection which doesn't contain any data:
foreach (DataRow row in myClass.ds.Tables["Editeur"].Rows)
editeurBox.Properties.Items.Add(row[1].ToString());
string TableSelect;
DataTable dt = GetSomeData();
foreach (DataRow row in dt.Rows)
{
TableSelect = "EmplNo = " + row["EmplNo"].ToString();
DataRow[] foundrows;
foundrows = dt.Select(TableSelect);
if (foundrows.Count() > 0)
{
//do something useful here :)
}
}
Data table result in grid:
SerialNumber PartNumber
000000001 QWERTY
000000002 QERTY
I need to search a particular SerialNumber in the result of my data table using a Textbox control.
Pseudocode example:
If
SearctTexbox.Text =000000001
Message: This Serial is Ok!
Else
Message: Not Ok
How to do this in LINQ or any other methods?
If SerialNumber column have unique values, so give it a try:
//dt is DataTable
dt.PrimaryKey = new DataColumn[1] { dt.Columns[0] }; // set your primary key
DataRow dRow = dt.Rows.Find(SearchTextbox.Text);
if (dRow != null){
// you've found it
}
else{
//sorry dude
}
Why do you need LINQ? You can try with
dataTable.Select("condition");
try this
var item = from r in Datatable.AsEnumerable()
where r.Field<int>("SerialNumber") == int.Parse(SearchTextbox.Text.ToString())
select r.Field<int>("SerialNumber");
if (item == null)
{
// not found
}
else
{
// you found it.
}
string massage = dc.Parts.Select(
o => o.SerialNumber == SearctTexbox.Text).Count()>0 ? "Found it"!"No Find";