Using LINQ's .Any() on a DataTable - c#

I have a datatable loaded up with some records and I am then pulling a query from another file and want to check if the ID that I pull in this query exists in my datatable.
foreach (var item in records)
{
bool hasit = dt.AsEnumerable().Any(p => p.Field<string>(0) == item.ID);
if (!hasit)
{
//Logic
}
}
I'm using that .Any() function and expecting it to return true if there is an ID in the first field of the datatable that matches the id in the records collection. It continually returns false though, am I missing something? Is there a better way to do this?

I'm using that .Any() function and expecting it to return true if there is an ID in the first field of the datatable that matches the id in the records collection. It continually returns false
When one uses == it compares object references. I recommend you instead use Equals which will just compare the values. Hence change your statement to
dt.AsEnumerable().Any(p => p.Field<string>(0).Equals(item.ID))
Which will achieve what you are expecting.

The method
.Any(p => p.Field(0) == item.ID)
will return true IF ANY element is found. Your posted code specifies that the next thing you do is ask
if (!hasit)
{
//Logic
}
which means if(NOT any has it)... which is producing the incorrect behavior. Change it to:
if (hasit)
{
//Logic
}
and you'll get the desired results.
Edit: kudos to Cuong Le for the observation.

I would try breaking it up to see if I could find the error:
foreach (var item in records)
{
var enumer = dt.AsEnumerable(); // <-- Check this to make sure it has elements
var filtered = enumer.Any(p => p.Field<string>(0) == item.ID); // <- Check to make sure it has elements
}

Related

How to set properties using Linq statement

Instead of doing this horrible loop which does achieve the desired result :
foreach (var mealsViewModel in mealsListCollection)
{
foreach (var VARIABLE in mealsViewModel.Items)
{
foreach (var d in VARIABLE.ArticlesAvailable)
{
d.ArticleQty = 0;
}
}
}
I'm trying to achieve the same result but with this linQ statement :
mealsListCollection.ForEach(u =>
u.Items.Select(o => o.ArticlesAvailable.Select(c =>
{
c.ArticleQty = 0;
return c;
})));
But the linQ statement does not reset ArticleQty to zero
What I am doing wrong? and why ?
Change your linq to ForEach cause Select does not iterate through collection in the way you want.
MSDN definition:-
Select Projects each element of a sequence into a new form.
ForEach Performs the specified action on each element of the List.
mealsListCollection.ForEach(u =>
u.Items.ForEach(o =>
o.ArticlesAvailable.ForEach(c =>
{
c.ArticleQty = 0;
})));
Use SelectMany to work through trees of nested lists. Use the ForEach function last to do the work:
mealsListCollection
.SelectMany(m => m.Items)
.SelectMany(i => i.ArticlesAvailable)
.ToList()
.ForEach(a => { a.ArticleQty = 0; });
What you are doing wrong is: select is returning your same collection, but has no effect until the objects are iterated over. Sitting in the foreach call, the selects are outside of the execution path. (Review comments for more information).
.select() in a call by itself does nothing special but determine what the returned list will look like.
.select().ToList() iterates over the collection, applying the projection.
If you were to set a variable equal to the .select call, but never access the data inside it, then the values would essentially still be what they started as. As soon as you iterate over, or select a specific element, it would then apply the projections.
Changing the selects to foreachs per vasily's comments will give you the desired results.
Can I perhaps suggest that you look to set the value equal to 0 further up your stack ( or down)? - Without knowing your use case, maybe there Is a better place to default it back to 0 than where you have chosen?
(automapper, Initializer, etc )

Storing results of multiple linq queries in IQueryable

I was wondering if it was possible to store the results of multiple linq queries in a single IQueryable statement?
I have a query which I use in a foreach:
//Where OnDemandHistory is the table
IOrderedQueryable<OnDemandHistory> A;
foreach (int id in machineID)
{
A = OnDemandHistory.Where(c => c.MachineID == id).OrderByDescending(c => c.ODHisDate);
// I want to Order all results before writing to the table
foreach(var entry in A)
{
// I add to a table based on all entries found in A
}
}
I am trying to get all entries where the machine ID match. The no. of MachineID's is varying (based on the user).
I was wondering if I can do a OrderByDescending after I have stored all the results from the query but before adding to the table.
I know due to the inner foreach loop that it won't happen, however when I try to do this:
foreach (int id in machineID)
{
A = OnDemandHistory.Where(c => c.MachineID == id).OrderByDescending(c => c.ODHisDate);
// I want to Order all results before writing to the table
}
foreach(var entry in A)
{
// I add to a table based on all entries found in A
}
I get a local variable A uninitialized error,
How would I go about solving this?
Thanks in advance
You can do it much simpler by using the Contains statement:
var result = OnDemandHistory.Where(c => machineID.Contains(c.MachineID))
.OrderByDescending(c => c.ODHisDate);
The error is caused because as the final result of your first query produces only the result of the last value of machineID this may result in either a null result or an uninitialisedvalue of A, so A needs to be initialised. Also, I suspect A could be a simple list.
You need something like:
A = new List<OnDemandHistory>();
foreach (int id in machineID)
{
A.AddRange(OnDemandHistory
.Where(c => c.MachineID == id).OrderByDescending(c => c.ODHisDate).ToList());
}
// order A here
Then run your second loop having checked that A has rows. However, I suspect there are smarter ways in LINQ of concatenating the machineID part of the query as a single LINQ statement.

The most efficient way to check records in a database exist, using Linq

I am using Linq and to check whether or not a record exists in the database and that it is the latest version. I can do this using Linq
bool query = db.foo.Any(x => x.Id == list.Id);
And then checking to see if this produced a true or false result.
The issue I have with this approach is that if I want to check all the attributes of the table to determine if the existing data differs from the new copy then it requires me to specify a mapping for each attribute and list item.
Is there a way I can iterate through or are there other alternatives available?
x refers to the Entity framework object that is representing the DB
list is a list that is mapped 1 to 1 to the Entity Framework object.
foo query = db.foo.Where(x => x.Id == list.Id).FirstOrDefault();
if(query != null)
{
properties = query.GetType().GetProperties();
foreach(PropertyInfo prop in properties)
{
if (list.GetType().GetProperty(prop.Name) != null)
{
var val1 = list.GetType().GetProperty(prop.Name).GetValue(list);
var val2 = prop.GetType().GetProperty(prop.Name).GetValue(prop);
// do your checking here
}
}
}
If I understand you correctly, you want a sort of for each loop to iterate over all the columns for a row, and check that they match the corresponding data from the list - is that correct?
The short answer is: Sorry, I don't think you can do that (at least not without using some reflection tricks, which might be rather messy, and will not perform as well as you probably want).
With SQL you can write: SELECT * FROM table (...), but there is no such option in Linq; you need to specify the names of each column explicitly.
What you could and probably should do instead, is what Jon Skeet mentioned briefly in a comment: Add a version number, or possibly a timestamp that you can check. Write your logic in such a way that you can be certain that if the version is correct/updated, then the row is valid.
You can then check the validity of a specific row by looking at it's version number. You could for instance do something like this:
// Does a row with specified ID exist and the newest version exist:
bool isRowValid = db.foo.Any(x => x.Id == list.Id &&
x.VersionNr == list.newestVersionNr);
bool chechExists = db.foo.Exists(x => x.Id == list.Id);
This will return bool as you wanted

How to change value of an object using linq

I have the following statment that if isdefault is true to this collection i need to set each object isDefault property to false.
custHead.lstCustomziation.Where(x => x.IsDefaultSelected == true).Select(x=>{x.IsDefaultSelected=false});
lstCustomziation is a collection.
LINQ is for querying. You should use a foreach loop to make changes:
foreach (var item in custHead.lstCustomziation.Where(x => x.IsDefaultSelected))
{
item.IsDefaultSelected = false;
}
That said, if IsDefaultSelected is false for the other items anyway, it may be simpler just to unconditionally set it:
foreach (var item in custHead.lstCustomziation)
{
item.IsDefaultSelected = false;
}
Linq is for querying, not updating. You can get a list of the items you want to change and then update using a normal loop:
var list = custHead.lstCustomziation.Where(x => x.IsDefaultSelected == true)
foreach(var item in list)
item.IsDefaultSelected=false;
As the Q of LINQ says, LINQ is designed for queries, not updates.
Just enumerate the LINQ result and apply your update.
Linq may have been initially created for querying but it has evolved and is used as functional programming methods, equivalents to "map", "reduce", and "filter" used in other languages.
In your example I would suggest:
var list = custHead.lstCustomziation.Where(x => x.IsDefaultSelected == true)
.Select(x=> TransformItem(x));
private XType TransformItem(XType item){
item.IsDefaultSelected=false;
return item;
}

First match in a collection

I want to convert this code to a linq solution. What it does it looks into a collection of customers and see if at least one of the has a middle name. This code works fine, I'm just trying to learn linq, so looking for an alternative solution.:
//Customers - List<Customer>
private bool checkMiddleName()
{
foreach (Customer i in Customers)
{
if (i.HasMiddleName == true)
{
return true;
}
}
return false;
}
I tried to write something like: (Customers.Foreach(x=>x.HasMiddleName==true)...
but looks line it's not the method I'm looking for.
If you just want to know if theres at least one, you can use Enumerable.Any:
bool atLeastOneCustomerWithMiddleName = Customers.Any(c => c.HasMiddleName);
If you want to know the first matching customer, you can use Enumerable.First or Enumerable.FirstOrDefault to find the first customer with MiddleName==true:
var customer = Customers.FirstOrDefault(c => c.HasMiddleName);
if(customer != null)
{
// there is at least one customer with HasMiddleName == true
}
First throws an InvalidOperationException if the source sequence is empty, whereas FirstOrDefault returns null if there's no match.
var result = Customers.Where(x=>x.HasMiddleName == true).FirstOrDefault();
Based on this:
What it does it looks into a collection of customers and see if at least one of the has a middle name.
Try
return Customers.Where(x => x.HasMiddleName).Any();
This query return true if at least one custmer has the property HasMiddleName = true
You may use the following to achieve what you need:
Customers.Where(cust=> cust.HasMiddleName).Count > 0
So , if Count is more than zero means you have some customers who have Middle name.
Or for better performance you may say:
bool customerWithMiddleName;
foreach(Customer cust in Customers)
{
if(cust.HasMiddleName)
{
customerWithMiddleName = true;
break;
}
}

Categories

Resources