choose a few id from db C# - c#

I have a database and excel file
And I want to export strings to excel
How to export strings with 1 id I know
The code you can see below
_Hours = Rep.Where(o => o.Projects.ProjectGroupID == 4).Where(o => o.Projects.ProjectType == 1).Sum(o => (decimal?)o.TaskEfforts) ?? 0m,
But how I can choose several id's?
This does not work
_Hours = Rep.Where(o => o.Projects.ProjectGroupID == 4).Where(o => o.ProjectDescriptionID == 10).Where(o => o.ProjectDescriptionID == 17).Where(o => o.ProjectDescriptionID == 18).Where(o => o.ProjectDescriptionID == 19).Where(o => o.ProjectDescriptionID == 21).Where(o => o.ProjectDescriptionID == 24).Where(o => o.ProjectDescriptionID == 26).Where(o => o.Projects.ProjectType == 1).Sum(o => (decimal?)o.TaskEfforts) ?? 0m,
I know, that it is an error, but how can I choose some ID's?
Thanks for answers.

The reason it didn't work is because each where clause is working on a subset of data that the previous one put out.
Use a list for your LINQ query's boolean logic.
List<int> ids = new List<int>{ 10, 17, 13, 7 };
_Hours = Rep.Where(o => ids.Contains(o.Projects.ProjectGroupID)).Where(o => o.Projects.ProjectType == 1).Sum(o => (decimal?)o.TaskEfforts) ?? default(int);
By manipulating the boolean this way, you can essentially convert a list of ints into a list of objects.
For your second where clause, I see you're needing a different attribute to restrict the list even further. This would work, since each where clause operates on the results of the first, but for the reader's sake it should be a &&.
_Hours = Rep.Where(o => ids.Contains(o.Projects.ProjectGroupID) && o.Projects.ProjectType == 1).ToList();

You're on the right track! As mentioned in the comments, you can use the || (OR) operator to select the o object if the id matches. In this case, you only need one Where. Here is your example written out:
_Hours = Rep.Where(o => o.Projects.ProjectGroupID == 4 || o.ProjectDescriptionID == 10 || o.ProjectDescriptionID == 17 || o.ProjectDescriptionID == 18 || o.ProjectDescriptionID == 19 || o.ProjectDescriptionID == 21 || o.ProjectDescriptionID == 24 || o.ProjectDescriptionID == 26).Where(o => o.Projects.ProjectType == 1).Sum(o => (decimal?)o.TaskEfforts) ?? 0m,
Edit: Didn't realize ProjectType property check at end of ORs. Made it it's own WHERE selector

Related

C# Entity Framework OrderBy Children's Children's with a where clause

I have a pretty complicated linq statement that gets a list of people (using Entity Framework) and I want to add an OrderBy clause to the end, depending on which column the user has clicked on for sorting. I DON'T want to get all the people and then sort as there are potentially alot of people and we also do paging, so getting the data and then sorting/paging is not an option. It must therefore be done using LINQ to EF.
I have managed to get the search criteria that filters based on the status of the user's current vaccination status, but I am unable to "convert" that to an OrderBy statement
The data I am getting relates to COVID vaccinations and whether the person's vaccination status is Full, Partial, Not Disclosed or None.
The Entity Framework LINQ statement with the Where clause looks like this and It is an IQueryable<Person>, not a List<Person>:
people.Where(p => p.Encounters.Where(e =>
e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
.EncounterItems.Where(ei =>
ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
(a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
))))).FirstOrDefault()
!= null)
From the above it will filter the people where their vaccination status is "Overdue". i.e they have done either Partial or Full Vaccination but the cycle for this vaccination has been exceeded. There are 2 questions with questioncode's "qIDateP" (partial) and "qIDateF" (full).
I know the below OrderBy is completly wrong, but I want to do something like this so that all the people with overdue vaccination status's are at the top. I will then add several other OrderBy clauses such as "Current" using the same clause, just chainging the date expression e.g. DbFunctions.AddMonths(a.adate, procedureCycleDays) >= DateTime.Today
people.OrderBy(p => p.Encounters.Where(e =>
e.EncounterItems.Any(ei => ei.PersonAssessments.Any(pa =>
pa.Assessment.Questions.Any(q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault()
.EncounterItems.Where(ei =>
ei.PersonAssessments.Any(pa => pa.Answers.Any(a => a.adate.HasValue && DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today &&
(a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase) || (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))
))))).FirstOrDefault()
!= null)
The Relationships for the EF Models is as follows:
Person => Encounter => EncounterItem => PersonAssessment => Answer
A person can answer multiple Assessments over their life and can change their mind as to whether they want to disclose their vaccination status or not.
NOTE: We are using the latest Entity Framework 6.4.4
I hope someone can help me with the OrderBy clause as Im at a complete loss as to how to achieve this.
------UPDATE 1-------
I have used this so far.
people.OrderBy(p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item
.EncounterItems.DefaultIfEmpty().FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)
The issue is that all the "Overdue" records are at the bottom, not at the top. If I use OrderByDescending it seems correct. How can I now put all those records at the top with OrderBy instead of OrderByDescending.
------ UPDATE 2 Final Solution ------
After a couple of changes based on Margus answer below I have the final updated OrderBy. I had to OrderBydescending for some reason in order to get the records that I wanted at the top.
people.OrderByDescending(p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase))))).OrderByDescending(e => e.servicedt ?? e.planneddt).FirstOrDefault() // you have 1 Encounters item.EncounterItems.DefaultIfEmpty().FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))).Encounter.planneddt)
Now Im concerned about the performance lol... But that will be another stackoverflow search :)
Well as far as I can tell you want to use orderBy and then simply fetch the first element, while you could simply fetch the first element with the same predicate dropping O(nlogn) complexity
var result = people.Where(
p => p.Encounters.Where(
e => e.EncounterItems.Any(
ei => ei.PersonAssessments.Any(
pa => pa.Assessment.Questions.Any(
q => q.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| q.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)))))
.FirstOrDefault(e => e.servicedt ?? e.planneddt) // you have 1 Encounters item
.EncounterItems.FirstOrDefault(
ei => ei.PersonAssessments.Any(
pa => pa.Answers.Any(
a => a.adate.HasValue
&& DbFunctions.AddMonths(a.adate, procedureCycleDays) < DateTime.Today
&& (a.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)
|| (a.Question.questioncode.Equals("qIDateP", StringComparison.InvariantCultureIgnoreCase)
&& (!pa.Answers.Any(aa => aa.adate.HasValue && aa.Question.questioncode.Equals("qIDateF", StringComparison.InvariantCultureIgnoreCase)))))))));

Linq optional parameters query

I am making a search form that queries my database to show results based on what has been filled out on the form. The only required field is the date which I have working. all the other fields are optional, if an optional field is not filled in it should not be a part of the query. This is the code I have written:
var queryable = context.TransactionJournal.Where(s => s.TransactionDateTime <= transactionDate)
.Where(s => Region == null || Region == s.AcquirerID)
.Where(s => MCC == null || MCC == s.MerchantCategoryCode)
.Where(s => MerchantID == null || MerchantID.Contains(s.MerchantID))
.Where(s => TxnCurrency == null || TxnCurrency.Contains(s.Currency))
.Where(s => TerminalID == null || TerminalID.Contains(s.TerminalID))
.Where(s => TxnAmount.ToString() == null || TxnAmount==(s.TransactionAmount))
.Where(s => BIN == null || BIN.Contains(s.Bin))
.Where(s => MsgType == null || MsgType.Contains(s.MessageType))
.Where(s => MaskedPan == null || MaskedPan.Contains(s.PANM))
.Where(s => ProcessingCode == null || ProcessingCode.Contains(s.ProcessingCode))
.Where(s => ClearPan == null || ClearPan.Contains(s.PAN))
.Where(s => ResponseCode == null || ResponseCode.Contains(s.ResponseCode))
.Where(s => AuthorizationCode == null || AuthorizationCode.Contains(s.AuthorizationCode))
.Where(s => EntryMode == null || EntryMode.Contains(s.PosEntryMode))
.AsQueryable();
Unfortunately it does not work correctly. Can someone tell me what I am missing or if there is a better way to write this?
Took advice from the comments and went through each line and found which line was evaluating false. This fixed my problem.
I think the best you can do there is check first if you should apply the condition and then filter the list.
An example using the code you provided.
var queryable = context.TransactionJournal.Where(s => s.TransactionDateTime <= transactionDate);
if (!string.IsNullOrEmpty(your_objet.Region)
{
var queryable = queryable.Where(x=>x.Region == your_objet.Region).AsQueryable();
}
if (!string.IsNullOrEmpty(your_objet.MCC)
{
var queryable = queryable.Where(x=>x.MCC == your_objet.MCC).AsQueryable();
}
The first line is the entire list, then you check all parameters that you have in the form and evaluate it, if has value the apply the filter to list.
And the end you'll get your list filtered.

C# linq multiple sorts in one clause

I'm trying to sort some data using Linq using two sorting methods but it doesn't work.
So I have a list that contains an Id and a Result.
I would like to sort in the following order:
Sort the list by the lowest ID wherever the Result = 0
Then sort the list by ascending Result
But the list can only include Results that are not null
I tried the code below but it appears I can't put a .Where in between the .OrderBy and the .ThenBy.
var selectedResults = Results
.OrderBy(s => s.id)
.Where(s => s.result == 0)
.ThenBy(s => s.result)
.Where(s => s.result != null)
.ToList();
Any suggestions?
You don't want to filter by s.result == 0 but just by s.result == null.
var selectedResults = Results
.Where(s => s.result != null)
.OrderBy(s => s.result == 0 ? s.id : s.result);
If you want to force that the result==0 items come first add this conditional order:
var selectedResults = Results
.Where(s => s.result != null)
.OrderByDescending(s => s.result == 0) // forces 0 results first even if there are negative
.ThenBy(s => s.result == 0 ? s.id : s.result);
Put ThenBy after OrderBy because it only works with IOrderedQueryable<T>, when you call Where it changes the return type back to IQueryable<T> so the ThenBy no longer be called. And as the comment points out, it is cheaper to filter the result set before ordering.
var selectedResults = Results
.Where(s => s.result == 0 && s.result != null)
.OrderBy(s => s.id)
.ThenBy(s => s.result)
.ToList();
If I understands you right,
var selectedResults = Results
.OrderBy(item => item.Result != 0) // items with Result == 0 first
.ThenBy(item => item.Result == 0 // if items.Result == 0 then by Id
? item.id
: int.MaxValue) // I've assumed id is int
.ThenBy(item => item.Result); // finally by Result
So we'll have something like this
Result | Id
-----------
0 | 1 <- Result == 0 on the top; tie breaks by Id (1, 2, 4)
0 | 2
0 | 4
-1 | 0 <- Result != 0 on the bottom, tie breaks by Result (-1, 7, 8, 9)
7 | 15
8 | 3
9 | 98
You always want to sort on the smallest dataset you can, so I would put the Where clauses at the beginning like so:
var selectedResults = Results
.Where(s => s.result == 0 && s.result != null)
.OrderBy(s => s.id)
.ThenBy(s => s.result)
.ToList();

LINQ: Filtering items List by some condition and do something with item by condition

Assume I have users which is List<User>, and User class has Type and Age properties.
I want to filter that list of users by some condition, and do something per item, based on condition. Let this list has 10 users, and some of them are of Type "complex" and some of them "simple". I want my final list to be users with age above 30, and if Type of user is "complex", to do something on it and then add it to final list. It should be something like:
var users= users.Where(u => u.Age > 30
and if u.Type = "complex" ? u = doSomething(u)).ToList();
and if doSomething(u) returns null, skip current "u" to be added to list.
It is half correct code and half like pseudo code because I don't know how to fit if u.Type = "complex" ? u = doSomething(u) part into LINQ expression. How can it be done?
EDIT: And how to do it if I want in final lsit users with Age > 30 OR users with Type = "complex" (and doSomething()) on complex users?
var users = users.Where(u => u.Age > 30) // common filter
.Select(u => u.Type == "complex" ? doSomething(u) : u) //select user or transformed
.Where(u => u != null) //not null only
.ToList();
Well, I came up with some sick variant...
public bool DoSomething()
{
// Do anything
return true;
}
var v = users.Where(x => x!= null && x.Age > 30 && x.Type == "Complex" && x.DoSomething() == true).ToList();
For your edit:
var v = users.Where(x => x!= null && (x.Age > 30 || x.Type == "Complex") && x.DoSomething() == true).ToList();
I would do something as follow :
users.Where(u => u.Age > 30).Select((u) =>
{
if (u.Type == "complex")
{
// Do something
}
return u;
}).ToList();
Select all users with age > 30 and then altering the result depending on the type property.
EDIT :
And for your Edit question just add the condition to the where :
[...].Where(u => u.Age > 30 || u.Type == "complex")[...]
AND QUERY
var andList = users.Where(u => u.Age > 30 && (u.Type == "complex" && doSomething(u) != null)).ToList();
OR QUERY
var orList = users.Where(u => u.Age > 30 || (u.Type == "complex" && doSomething(u) != null)).ToList();

Comparing nullable datetime

I am trying to compare dates in my linq query but my c.DateRequired is a nullable date field and I want to just compare the date without the time. How do I go about converting c.DateRequired in this case to just get the date.
IEnumerable<SalesOrder> salesOrders = _uow.Repository<SalesOrder>().Query()
.Filter(c => c.IsDeleted != true &&
(((c.DateRequired == DateTime.Today.Date)) && Period == 1) ||
(((c.DateRequired >= sDateP && c.DateRequired <= stDate)) &&
(Period == 2 || Period == 3)))
.OrderBy(q => q.OrderBy(c => c.DateCreated))
.Get()
.Select(p => new
{
SalesOrder = p,
SalesOrderDetailsList =
p.SalesOrderDetailsList.Where(pd => pd.IsDeleted != true),
salesOrderDetailsComponentsList =
p.SalesOrderDetailsList.Select(c => c.SalesOrderDetailsComponentsList),
SalesOrderDetailsComponentsInfoList =
p.SalesOrderDetailsList.Select(
i =>
i.SalesOrderDetailsComponentsList.Select(
info => info.SalesOrderDetailsComponentsInfoList))
})
.ToList()
.Select(p => p.SalesOrder);
return salesOrders;
}
Try to use something like this:
.Where(x => x.DateRequired.HasValue &&
EntityFunctions.TruncateTime(x.DateRequired.Value) == EntityFunctions.TruncateTime(DateTime.Today))
.ToList();
It works perfectly for me.
you need to use EntityFunctions.TruncateTime which accept a nullable datetime to truncate time in linq
EntityFunctions.TruncateTime(x.DateRequired) == EntityFunctions.TruncateTime(DateTime.Today)
I answer to a similar question.
The recommended way to compare dates in linq queries if you are using EntityFramework 6 is DbFunctions.TruncateTime(m.PlanDate) and for previous versions EntityFunctions.TruncateTime(m.PlanDate)

Categories