Conditional LINQ query in foreach - c#

I have a multiselection box and I would like to iterate over the selected items and do a linq query, but I'm not sure how to write it. This is what I have so far:
if (lbStateLegislation.Items.Count > 0)
{
foreach (ListItem li in lbStateLegislation.Items)
attributes = vdc.attributes.Where(a => a.fieldvalue == li.Value).ToList();
}
I basically need to construct an OR query, so it is selecting from the collection where there are values for each of the selected items. I think, as it's written now, it is doing an AND query.

Just use the Contains extension method. Linq2Sql will translate it as an IN clause:
var inValues = lbStateLegislation.Items.Select(s => s.Value);
vdc.attributes.Where(a => inValues.Contains(a.fieldvalue));
You may be able to combine the two statements into one, but I will leave that for you to try as I'm not positive that it will work as a single statement.
HTH

var attributes=
vdc.attributes.Where(q=>
lbStateLegislation.Items.Any(o=> o.Value == q.fieldValue))
.Select(o=> o);

Related

Remove an item from a list

why cant I select remove or delete? I want to remove a record from a list
IEnumerable<StockLocation_Table> AllCurrentStocklocations = db.StockLocation_Table.ToList();
List<StockLocation> StockLocations = ServerHelper.GetStockLocationsBatch(BatchUrl, i, batchSize);
foreach (StockLocation_Table _stock_table in AllCurrentStocklocations)
{
foreach (StockLocation _stock in StockLocations)
{
if (_stock.ServerLocationId == _stock_table.ServerLocationId)
{
AllCurrentStocklocations.?? why cant i say remove._stock_table
}
}
}
Because it is IEnumerable<T> and the Remove method is not defined in IEnumerable<T>.Since you are using ToList just use a List<T> as type:
List<StockLocation_Table> AllCurrentStocklocations = db.StockLocation_Table.ToList();
Edit: Also you can't modify the collection inside of foreach loop.You can use LINQ instead:
var AllCurrentStocklocations = db.StockLocation_Table
.Where(x => !StockLocations
.Any(s => s.ServerLocationId == x.ServerLocationId).ToList()
What you want to do here is get all of the items from your DB table where the ID is not in this other list. What you should do here is construct a query such that you get just those items without those IDs, rather than pulling down the entire DB table into a list, and then going through this other list for each item) to look for IDs so that you can remove the current item from this list. In addition to being super inefficient, this would also mean removing the item from a collection being iterated, which would break the iterator. Instead write something that can be translated into a DB query:
List<StockLocation> stockLocations = ServerHelper.GetStockLocationsBatch(
BatchUrl, i, batchSize);
var locationIDs = stockLocations.Select(location => location.ServerLocationId);
db.StockLocation_Table.Where(item =>
!locationIDs.Contains(item.ServerLocationId));

Using linq to iterate through winform menuitems and change a property value

I have a context menu. I went to iterate through all the menu items and disable or enable them based on a some boolean value.
This is what I have so far, but it doesn't work:
contextMenu.MenuItems.Cast<MenuItem>().Select(x =>
{
x.Enabled = someValue;
return x;
});
Use a simple foreach loop for update your values, LINQ is for querying
foreach(var item in contextMenu.MenuItems.OfType<MenuItem>())
{
item.Enabled = someValue;
}
The closest thing is the ForEach method on List<T>. I don't this that it's technically considered LINQ and unlike the core LINQ to Objects methods it's not part of IEnumerable<T>. Anyway, I'm guessing you'll prefer it to a traditional foreach loop since it looks like any other LINQ query using method syntax.
contextMenu.MenuItems.Cast<MenuItem>().ToList().ForEach(x => x.Enabled = someValue);

Convert nested for each loop to LINQ

I have a for each loop to get data which is very time consuming.any suggestion to convert this to linq. Thanks in advance.
iListReport = obj.GetClosedReports();
string sRepType ="";
foreach (ReportStatisticsInfo item in reportStatistic)
{
sRepType = item.ReportName.Trim();
IList<string> lastClosedReport = new List<string>();
foreach (TaskListInfo taskInfo in iListReport)
{
string reportName = taskInfo.DocumentName.Trim();
if (string.Compare(sRepType, reportName, true) == 0)
{
if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close) && !lastClosedReport.Contains(taskInfo.DocumentID))
{
iClosedreportCount += 1;
lastClosedReport.Add(taskInfo.DocumentID);
}
}
}
}
Here you go. I've done a pretty literal translation of your code into LINQ which will hopefully help you to see how I've converted it.
Note the use of the let keyword which allows you to declare a range variable (which allows you to perform your trim once and then use the result in multiple places).
Also note the use of group by at the bottom of the LINQ query to ensure we only take the first occurence of each documentID.
IList iListReport = obj.GetClosedReports();
var query = from item in reportStatistic
let sRepType = item.ReportName.Trim()
from taskInfo in iListReport
let reportName = taskInfo.DocumentName.Trim()
where string.Compare(sRepType, reportName, true) == 0
&& taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
//here's how we make sure we don't get the same documentID twice
//we group by the id and then take the first
group taskInfo by taskInfo.DocumentID into grouping
select grouping.First().DocumentID;
var lastClosedReport = query.ToList();
iClosedreportCount = lastClosedReport.Count;
How to convert a foreach loop to LINQ
Here are some comparisons of your code against LINQ version to help you out if you've got to do a conversion again sometime. Hopefully this will help anyone else out there that has got to convert a foreach loop to LINQ.
1. foreach and from
You can perform a straight swap of the foreach clause for a LINQ from clause. You can see that this:
foreach (ReportStatisticsInfo item in reportStatistic)
has become this:
from item in reportStatistic
2) Variable declaration and the let keyword
When you declare variables within your foreach, you can swap them out for the LINQ let statement. You can see that this declaration:
sRepType = item.ReportName.Trim();
has become:
let sRepType = item.ReportName.Trim()
3) if statements and the where clause
Your if statements can go inside the where clause. You can see that the following two if statements:
if (string.Compare(sRepType, reportName, true) == 0)
if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
have become this where clause
where string.Compare(sRepType, reportName, true) == 0
&& taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
4) Using group by to remove duplicates.
It's all been quite simple so far because everything has just been a straight swap. The most tricky part is the bit of code where you prevent duplicates from appearing in your result list.
if (taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
&& !lastClosedReport.Contains(taskInfo.DocumentID))
{
iClosedreportCount += 1;
lastClosedReport.Add(taskInfo.DocumentID);
}
This is tricky because it's the only part that we have to do a bit differently in LINQ.
Firstly we group the 'taskInfo' by the 'DocumentID'.
group taskInfo by taskInfo.DocumentID into grouping
Then we take the first taskInfo from each grouping and get it's ID.
select grouping.First().DocumentID;
A note about Distinct
A lot of people try to use Distinct to get rid of duplicates. This is fine when we're using primitive types, but this can fail when you're using a collection of objects. When you're working with objects Distinct will do a reference comparison of the two objects. This will fail to match objects that are different instances but happen to have the same ID.
If you need to remove duplicates based upon a specific property within an object, then the best approach is to use a group by.
With LINQ you'll get a single IEnumerable<string> with duplicates
from item in reportStatistic
from taskInfo in iiListReport
where (string.Compare(item.ReportName.Trim(), taskInfo.DocumentName.Trim(), true) == 0)
&& taskInfo.ActionID == Convert.ToInt16(ReportAction.Close)
select taskInfo.DocumentID
You can then Distinct().GroupBy(d => d.taskInfo)

Finding matches that contain certain text in properties using LINQ

I am trying to convert the following code to LINQ
foreach (var item in pageHistorycol)
{
if (item.PageTitle.Contains(text) || item.PageURI.Contains(text))
{
tempHistory.Insert(0, item);
}
}
The following returns all items instead of the matches
var matches = pageHistorycol.Where(item =>
(item.PageTitle.Contains(text) || item.PageURI.Contains(text)));
What am I missing?
The two statements you displayed should return the same items. If the second returns all items, the foreach loop should add all of the items to tempHistory as well.
The main difference will be your foreach loop will return the items in the opposite order as your LINQ query. If the order of matches is important, you can get the items in the same order using:
var matches = pageHistorycol
.Where(item => item.PageTitle.Contains(text) || item.PageURI.Contains(text))
.Reverse();

how to select an item from generic list by linq

I have a LINQ query which contains a method GetInstanceForDatabase()
principlesList.Select(p => p.GetInstanceForDatabase()).ToList()
where
List<PrincipleInstance>() principlesList = ...
// (contains list of principle like "Manual Trades", "OPM", "Flora")
GetInstanceForDatabase() is a method which takes all other info about a principle (like manual trades).
My problem is that I want to sort out only principle like only "Manual Trades".
I want to put a where clause. I tried but it is fails.
To get a single item use:
query.First(x => x.property == "Manual Trades");
// or
query.FirstOrDefault(x => x.property == "Manual Trades");
var list = p.GetInstanceForDatabase().where(x => x.propertyName == "Manual Trades").ToList();
I'm sure you're GetInstanceForDatabase needs to return your collection that you then filter for the 'Manual Trades' but I can't really tell how you get your list of PrincipalInstances from the question.
This is the correct syntax of using Where in LINQ
principlesList.Select(p => p.GetInstanceForDatabase()).Where(p => p.SomeProperty == "SomeValue").ToList();

Categories