DataGridView Filtering OnClick Event (C# WinForm) - linq

How to filter my datagridview by the value of my label.text on click event? That value is from my linq query:
dataSet.Tables[0].AsEnumerable().Where(c => c.Field<int>("ageColumn") > 3 &&
c.Field<int>("ageColumn") < 5).Count();
Let's just say the above query gives me 12 (label.text = 12), now when I click "12", I want my datagridview to ONLY show those 12 rows that meet my above query.

Do you need it to be dynamic? Perhaps store the query itself as a lambda in the Tag property of your label:
Predicate<DataColumn> clause = c => c.Field<int>("ageColumn") > 3
&& c.Field<int>("ageColumn") < 5;
label1.Tag = clause;
... then re-evaluate your query when the label is clicked:
var clause = (sender as Label).Tag as Predicate<DataColumn>;
myDataSource = dataSet.Tables[0].AsEnumerable().Where(clause);
I don't know if this would work, but at least it would let you "attach" a where-clause to various lables.
I'd also recommend taking a look at Bindable LINQ so the results of your queries can be bound to. Very cool stuff.

Now I do not use LINQ, but logic would suggest that whatever is retured by the expression
dataSet.Tables[0].AsEnumerable().Where(c => c.Field<int>("ageColumn") > 3 &&
c.Field<int>("ageColumn") < 5)
Contains the data you seek? Is there not a property in there to enumerate the data?

Related

Restricting deeply-nested child records returned using LINQ

Given this object structure, how do I bring back a WorkItem, it's report(s), row(s) and student(s), but only the row whose Student's name is 'Bob' (I want to omit the rows containing 'Alice' and 'Claire').
WorkItem
----Report1 (held in WorkItem.Reports collection)
--------ReportRow1 (held in Report.ReportRows collection)
------------Student.Name = 'Alice'
--------ReportRow2 (held in Report.ReportRows collection)
------------Student.Name = 'Bob'
--------ReportRow3 (held in Report.ReportRows collection)
------------Student.Name = 'Claire'
(sorry about the formatting)
I thought something like this would work, but it still brings back all 3 rows
WorkItem found = (from workItem in session.Query<WorkItem>()
from report in workItem.Reports
from row in report.ReportRows
where workItem.Id == 1 && row.Student.Name == "Bob"
select workItem)
.SingleOrDefault<WorkItem>();
Update
I also tried this, thinking it would only bring back the results when I actually try to use them (which it does) but looking at the logs, it still does a select for each student (I was hoping the 'where' clause in the final foreach loop would bring back just the one I was interested in.
var query = from workItem in session.Query<WorkItem>()
where workItem.Id == 1
select workItem;
WorkItem found = query.SingleOrDefault<WorkItem>();
foreach (var report in found.Reports)
{
foreach (var row in report.ReportRows.Where(x => x.Student.Name == "Bob"))
{
Console.WriteLine("--" + row.Student.Name);
}
}
This is my current best stab at it based on help from Ocelot20:
var result = (from workItem in session.Query<WorkItem>()
.FetchMany(x => x.Reports)
.ThenFetchMany(y => y.ReportRows.Where(z => z.Student.Name == "Bob"))
where workItem.Id == 1
select workItem);
The only thing that doesn't work is the Where clause for the student name. If I remove that, I get a result back (albeit with too many rows). If I can get the where clause right I think it will be bringing back what I want
From what I can see here, you are only selecting a WorkItem. You are doing joins that limit the WorkItems that are returned, but you are still only selecting a WorkItem and not telling it to select specific Reports, ReportRows, etc. So essentially your query is saying: "Give me only WorkItems with an Id of 1 that can be joined with students named Bob". Note the lack of: "Then select that WorkItem with only the appropriate ReportRows.
My guess is that you're doing something like this:
WorkItem found = (from workItem in session.Query<WorkItem>()
from report in workItem.Reports
from row in report.ReportRows
where workItem.Id == 1 && row.Student.Name == "Bob"
select workItem).SingleOrDefault<WorkItem>();
// Doing something to select `ReportRows` without filtering them:
var someSelection = found.Reports.First().ReportRows;
Depending on how you have lazy loading set up, ReportRows will not even be queried until you call it on the someSelection line. At this point, it knows nothing about what you want to filter on. You have a couple of options here. First, you can just filter the items in the second query once you have already loaded the WorkItem like so:
// Filter on the second query:
var someSelection = found.Reports.First().ReportRows
.Where(rr => rr.Student.Name == "Bob");
Or you could just change up your query to explicitly select the work item and related rows: select new { workItem, reportRows = // select specific rows with a where clause here. }.
Lastly, there's the nhibernate ability to specify what related entities should be preloaded into your selected entity. I know entity framework lets you add Where clauses on the related entities, but I haven't used nhibernate to know whether or not you can do something like this:
var customers = session.Query<Customer>()
.FetchMany(c => c.Orders.Where(o => o.Amount == 100);
If this works, this could be applied to your query to tell nhibernate to load the WorkItem with related rows where the Student name is "Bob".

Datatable linq select query

I m trying to select a column's value from a datatable based on conditions.
var results = from DataRow myRow in dtCallBack.AsEnumerable()
where myRow.Field<DateTime>(1) == startDateTime
&& myRow.Field<int>(0) == callBackID
select myRow.Field<int>(3);
My datatable contains 4 columns ID,Date1,Date2,IntVal
I want to convert the variable results to int. (I want to return the column 4 IntVal)
var results = (from DataRow myRow in dtCallBack.AsEnumerable
where myRow.Field<DateTime>(1) == startDateTime
&& myRow.Field<int>(0) == callBackID
select myRow.Field<int>(3)).SingleOrDefault();
Well you've currently got an IEnumerable<int> by the looks of it. So which of those results do you want? What do you want to happen if there aren't any results?
If you're confident there's only a single result, you can use:
var result = results.Single();
If you want the first result or 0 if there aren't any, you could use
var result = results.FirstOrDefault();
If you want the first result and an exception if there aren't any, you could use
var result = results.First();
Basically there are lots of options, and you'll need to clarify your requirements before we can really give you a more concrete answer.

LINQ: Can I get a property from an object in a list, within a collection?

foreach (ReportType t in reportsCollection)
{
List<Report> reps = (from r in t.reports where r.isChecked == true select r).ToList<Report>();
foreach (Report r in reps)
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(r.path));
}
This statement works just fine. I'm just looking for a single LINQ statement that could maybe do this.
Basically, I have a report object with a property called isChecked. reportsCollection contains several reportTypes that contains lists of reports of that type. So the collection looks like this:
type1
report
report 2
report 3
type 2
report 4
report 5
report 6
and so on.
I want a LINQ statement that will grab all reports where isChecked == true within those types. I suspect a loop is necessary, but I was curious to see if the community had a solution. Thanks!
You want to use SelectMany
var query = reportsCollection.SelectMany(t => t.reports)
.Where(r => r.isChecked == true)
.ToList();
In query expression syntax form, you might write it as
var query = (from type in reportsCollection
from report in type.reports
where report.isChecked == true
select report).ToList();
In query syntax it will look like this
var query = from t in reportCollection
from r in t.reports
where r.isChecked == true
select r;

linq where according to selected item?

I am new to EF and LINQ, hoping to get some answers here.
I am trying to search from list with where condition that is according to the selecteditem from a combobox.
The combobox has 15 items(all bit datatypes) but let me just narrow it down to 2 for examples sake. items are( pro bono, civil)
Now I have a list called listOfAllNeutrals (object name is Neutral with properties such as pro bono (bit) and civil(bit), and I want to filter it using the where condition according to the selected item.
so if selected item = pro bono, the linq would look like this
var result = from n in listOfAllNeutrals
where n.probono==true
select n;
but my prob is how do I tell that the n.property should be according to the selecteditem?
like this:
var result = from n in listOfAllNeutrals
where getpropertyName==true
select n;
is there a simpler way, I don't want to use If conditions if possible.
You need to use if's or switch inside the getpropertyName(Neutral objNeutral) function to Map the selected item to the property you want to evaluate and evaluate it. You need to map object => property in some way.
Try
var result = from n in listOfAllNeutrals
where (selectedItem == proBono && n.probono == true)
|| (selectedItem == civil && n.civil == true)
select n;

LINQ to SQL, sorting by a related table

I'm trying to order the values in a related table using LINQ to SQL.
I have 2 tables. Menu and MenuSection. They are related one to many on Menu.MenuId == MenuSection.MenuId
Currently, I'm pulling this information using the following query
var menus = from m in _context.Menus
select m;
This gets fed into an ASP.NET MVC page and works fine.
I'd like to be able to sort the data the column MenuSection.Order
I've tried doing this:
var menus = from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
orderby ms.Order ascending select m;
But it's bringing back a set of data that is incorrect. It displays repeated Menu information.
EDIT: To clarify what i'm expecting the data shoud be:
There are x Menu's in Menu.
Each Menu has many MenuSection's
I'd like to list out each Menu and their related MenuSection.
The MenuSections need to be in order based on MenuSection.Order
Menu 1
- MenuSection 1, Order = 1
- MenuSection 3, Order = 2
Menu 2
- MenuSection 4, Order = 1
- MenuSection 2, Order = 2
Round 3: That last revision to the question clarifies it a lot. It sounds like what you really need is a group-by. Those are harder to get right without the IntelliSense but I'll try my best:
var groupings =
from m in _context.Menus
orderby m.Foo
from ms in m.MenuSections
orderby ms.Order
group ms by m;
foreach (var group in groupings)
{
Menu menu = group.Key;
// use the Menu
foreach (MenuSection ms in group)
{
// use the MenuSection
}
}
Now I added an extra orderby m.Foo where Foo is some property that I think you might want on Menu. Otherwise you aren't guaranteed to know the order of the top level menus.
Also note what I was saying earlier that the m.MenuSections is really a helper that is similar to from ms in _context.MenuSections where ms.MenuId == m.MenuId.
have you tried something like this? ...
var menus = (from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
orderby ms.Order ascending select m).Distinct();
or maybe this...
var menus = (from m in _context.Menus
join ms in _context.MenuSections on m.MenuId equals ms.MenuId
select new {m, ms.Order})
.OrderBy(x => x.Order)
.Select(x => x.m)
.Distinct();
In that second case, you're projecting the sort column into a new type, sorting on it, then selecting just the original object, and distincting on that.
Just an FYI, I did manage to make this work by sorting as I performed the output.
My original intention was to have a presorted data set to work with.
Here is an example of what I meant:
var menus = from m in _context.Menus select m;
foreach (var menu in menus)
{
Console.WriteLine(menu.Name);
foreach (var menuSection in menu.MenuSections.OrderBy(o => o.Order))
{
Console.WriteLine("\t" + menuSection.Name + ", " + menuSection.Order);
}
}

Resources