简体   繁体   中英

Applying multiple variable where clauses to linq query

I am creating a utility using a line to sql query which will load data in a datagrid.

As the data set is in excess of 80,000 records, filtering is handled by the linq query to keep the filtering off the UI thread. I cannot filter the data grid using a filter in WPF directly as applying the filter is handled soon the UI thread, which locks the window for the 3 minutes that the filter takes to apply.

The filtering options are controlled by a number of switches (the function as checkboxes), returning bool if checked.

I want to use these switches to affect the line query, for example, if the option of completed items is checked, the equivalent change to the line query would be to add completed equals true as a where clause, however if they are not checked, I simply wish to ignore the option.

To clarify, if the check box to show completed items is not checked, I want to show all items whether completed, or not completed. If the check box to show completed items is checked, I want to show all items where completed is equal to true.

Currently, I am adding clauses to a query object called query in the form query = query.Where(r => r.completed == true) , however these need to be wrapped in an if statement - I cannot simply take the value of the switch as I want to ignore the filtering if the switch is false rather than specifically add a condition which checks a certain property is set to false.

Is there anything provided as a part of linq for implementing a variable line query in this way, or is the if block the way to go about it?

Although this has been marked as a possible duplicate, I'm not certain that it is in that the solution to the other question is to use an if statement which is what I'm looking to avoid. That question was also asked over 8 years ago, and the .NET platform has changed a lot since then. I'm aware that I can use multiple if statements to handle this, but if there is an alternative which is more efficient and/or easier to read, I'd like to use it.

As code has been asked for,

                IsBusy = true;
                String sqlConnect = connectionString;
                DbConnection connection = EFConnectionFactory.MakeConnection(sqlConnect);

                using (var db = new DbContext(connection)) {

                    var query = from l in db.Batch
                                join d in db.Document on l.id equals d.batch_id
                                group d by new { batchId = l.id, l.batchName, Added = l.added, Status = l.status, PaginationLocked = l.OKDate } into g
                                select new {
                                    BatchId = g.Key.batchId, BatchName = g.Key.batchName, CreatedDate = g.Min(t => t.added), g.Key.PaginationLocked, FinalisedDate = g.Max(t => t.OKDate), g
                                } into res
                                select new BatchChronologyDataModel {
                                    BatchId = res.BatchId,
                                    BatchName = res.BatchName,
                                    TotalDocuments = res.g.Count(),
                                    TotalOKayed = res.g.Where(s => s.documentOKayed != null).Count(),
                                    TotalExported = res.g.Where(s => s.editLocked != null).Count(),
                                    CreatedDate = res.g.Min(t => t.added),
                                    Status = res.g.Key.Status,
                                    PaginationLocked = res.PaginationLocked != null,
                                    FinalisedDate = res.g.Max(t => t.OKDate),
                                    DurationDays = DbFunctions.DiffDays(res.CreatedDate, res.FinalisedDate),
                                    BatchAgeDays = DbFunctions.DiffDays(res.CreatedDate, DateTime.Now),
                                    IsCompleted = res.g.Max(t => t.OKDate) != null,
                                };



                if (this.ShowLongCycleBatches) {
                    query = query.Where(r => r.DurationDays > 3);
                }

                if (this.Completed) {
                    query = query.Where(r => IsCompleted == true);
                }

The issue here is simply that I have multiple clauses which have to be applied in a certain order, ie all batched completed will remove all uncompleted items when it runs.

I wish to show the whole data set, and filter out anything which does not match the conditions if and only if an option is selected. I do not want to assume that not checking a box is equivalent to a false value.

As there are a lot of selectable options, I'd like to know if there is a way to avoid multiple if statements - I'm not saying that I have an issue with them, but I'd worked on solutions before where I've not spotted something useful and implemented a huge solution when there was a better answer.

The solution in this case which worked for me was to use the Dynamic Expression API to form up a query in the form of a string (akin to an SQL query), and run this directly on the query in the form query.Where("Status=hidden and BatchAgeDays>10"); .

Although expression trees would be a usable solution, this form is less verbose and more readable, and overall a great deal less work to implement, and allows multiple clauses to be concatenated into a single call to Where .

https://github.com/kahanu/System.Linq.Dynamic/wiki/Dynamic-Expressions

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM