I have entities that are nested in this order:
RootDomain
Company
CompaniesHouseRecord
CompanyOfficer
When given a RootDomain I want to create a list of all CompanyOfficers that have an email address but I am not sure how to do this.
Here Is my non-working attempt:
RootDomain rd = db.RootDomains.Find(123);
List<CompanyOfficer> col = rd.Companies.Where(x => x.CompaniesHouseRecords.Any(chr => chr.CompanyOfficers.Any(co => co.Email != null)))
.Select(x => x.CompaniesHouseRecords.Select(chr => chr.CompanyOfficers)).ToList();
I am obviously way off the mark here. Can someone show me or point me to the correct method for dong this?
Like this:
RootDomain rd = db.RootDomains.Find(123);
List<CompanyOfficer> col = rd.Companies
.SelectMany(c => c.CompaniesHouseRecords)
.SelectMany(c => c.CompanyOfficers)
.Where(o => null != o.Email).ToList();
Someone answered before me, but I can show something different, which can be more convenient for someone who is used to DB requests.
Using LINQ, you can do this type of request:
var officersWithEmail = from company in rd.Companies
from companiesHouseRecord in company.CompaniesHouseRecords
from companyOfficer in companiesHouseRecord.CompanyOfficers
where (companyOfficer.Email != null)
select companyOfficer;
Some people will find it more readable.
If you want to obtain a List<> as output, just use .ToList on the query.
Related
I am trying to generate a List<Object> using Where clause with properties from a different List<Object>. I know that I could use a .Include(), similar to a SQL join if I were using Entity Framework but I am not using Entity Framework so I don't think it would work. I have:
List<Problem> problems = MethodToCallDbAndGenerateList(); //ado.net
problems = problems.Where(x => x.Property1 == "value").ToList();
//remaining logic
List<Solved> solved = MethodToCallDb()
.Where(x => x.SolvedId == problems.ProblemId)
.ToList();
//error happens in Where(...problems.ProblemId);
//List<Problem> does not contain a definition for ProblemId
The error says the List<Problem> does not contain ProblemId but I do have that property in my class. So I am unsure of why I am getting that error.
How can I generate my List<Solved> based on filtered results from
.Where(x => x.SolvedId == problems.SolvedId);
Using LINQ to Objects, you can use the Enumerable.Join method to create a join between two List<T>s and just return the matching members:
List<Problem> problems = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.ToList();
List<Solved> solved = MethodToCallDb()
.Join(problems, s => s.SolvedId, p => p.ProblemId, (s,p) => s)
.ToList();
However, if there are a lot of problems and solved, or if you frequently check the same list of problems, or if you are only creating problems to use in the join, you'd be better off creating a HashSet:
var problemIDs = problems.Select(p => p.ProblemId).ToHashSet();
List<Solved> solved = MethodToCallDb()
.Where(s => problemIDs.Contains(s.SolvedId))
.ToList();
NOTE: If you are only creating problems to use in the join, better to skip creating the List<Problem> and just do:
var problemIDs = MethodToCallDbAndGenerateList()
.Where(x => x.Property1 == "value")
.Select(p => p.ProblemId)
.ToHashSet();
var reassignForms = _formQueryRepository.WithRelatedEntities()
.Where(x => x.Id == formId && x.SchoolId == schoolId)
.Select(y => y.FormUsers.Where(m => m.CanEdit).Select(z => new ReassignFormDTO
{
Name = z.UserProfile.FullName,
Id = z.UserProfile.Id,
Email = z.UserProfile.Email,
Role = z.UserProfile.UserRole,
}));
I want to convert it to ReassignFormDTO but somehow it is returning an object which I cannot convert. I want this to be direct object not [0].objects.
You can use .FirstOrDefault() then it will return the first entity from the linq query. According to the debug window you have two ReassignFormDTO objects and seems like you would like to get only one.
Please provide more detail, so we can help more. Not sure if my previous answer will help you.
EDIT: I didn't noticed the second select inside you statement. According to the comments .SelectMany(z => z) should help you out.
Hopefully this question is not to confusing. Basically I'm looking for pointers on how to OrderByDecending with a date from relational tables. I have constructed a basic method that looks like it could possibly work but I'm getting errors:
DbSortClause expressions must have a type that is order comparable.
Parameter name: key
I understand what this is saying but I'm not entirely sure how to fix using Linq method syntax.
public BusinessEntities.Application GetLastUpdatedAppliction(int userID)
{
return context.tbl_User_To_Application
.Where(x => x.UserID == userID)
.OrderByDescending
(o => o.tbl_Application.tbl_ApplicationChanges
.Where(oo => oo.ApplicationID == o.ApplicationID)
.Select(s => s.ChangeDate))
.ThenByDescending(t => t.DateAdded)
.Select(y => new BusinessEntities.Application
{
ApplicationID = y.tbl_Application.ApplicationID,
ApplicationName = y.tbl_Application.ApplicationName
}).FirstOrDefault();
}
Basically I have a cross reference table that binds a user to a specific application(Website) Then inside I need to nest into two tables to get the latest changes to the Application with a "ChangesDate". So ideally this would return the last updated application. Then obviously populates my DTO.
I'm still trying to get to grips with Linq method syntax so any help would be greatly appreciated!
Regards,
Tez Wingfield
If you want to order by the last application change date:
(...)
.OrderByDescending(o =>
o.tbl_Application.tbl_ApplicationChanges
.Where(ac => ac.ApplicationID == o.ApplicationID)
.OrderByDescending(ac => ac.ChangeDate)
.First()
.Select(ac => ac.ChangeDate)
)
(...)
I have got a table for Comments like following:
Comment{
ID,
Text,
ParentID
}
I am using following query to select the popular comments with paging based on number of replies.
var comments = db.Comments
.OrderByDescending(c => db.Comments.Count(r => r.ParentID == c.ID)).Skip(skip).Take(recordsPerPage).ToList();
Please let me know the best way of handling this situation when we have thousands of comments?
I would consider adding an extra column to Comment that stores the replies count.Then instead making a nested query you can easily order your Comments by replies count.
var comments = db.Comments.Skip(skip).Take(recordsPerPage)
.OrderByDescending(c => c.ReplyCount)
.ToList();
Unless you are prepared to pre-calculate this in the database then you have the problem that you need to either do nested queries or to do a single full fetch an then do everything in memory. The latter is my choice until it is proven to be too slow.
Here's how I'd initially do it.
First, pre-fetch:
var allComments = Comments.ToArray();
Then create a function that will quickly return the count of comments:
var childrenLookup = allComments.ToLookup(x => x.ParentID);
var parentMap = allComments.ToDictionary(x => x.ID, x => x.ParentID);
Func<int, int> getCommentsCount = n =>
{
var r = 0;
if (parentMap.ContainsKey(n))
{
r = childrenLookup[parentMap[n]].Count();
}
return r;
};
Now it is almost trivial to return the results:
var comments = allComments
.OrderByDescending(c => getCommentsCount(c.ID))
.Skip(skip)
.Take(recordsPerPage)
.ToList();
(And, yes, your ordering is in the wrong order to you skip and take for paging.)
If you can't do this in memory then go with the pre-calculate approach.
This is the query I am trying to do.
var commentActivity = project.ProjectDoc
.Select(c => c.Comment.Select(i => i.UserID))
.Distinct()
.Count();
What I want is the number of comments from distinct users on a specific project, but ANY ProjectDoc. This query "works" the result is just wrong. The model is like this, generically sketched.
Project
ProjectDoc
Comment
Update: I had to go one level deeper, based on the answer below I tried a few things that didn't work so I though I would post this as a reference. Note the two SelectMany methods.
var replyActivity = project.ProjectDoc
.SelectMany(c => c.Comment.SelectMany(r => r.CommentReply.Select(u => u.UserID)))
.Distinct()
.Count();
Use SelectMany instead of Select
project.ProjectDoc
.SelectMany(c => c.Comment.Select(i => i.UserID))
.Distinct()
.Count()
var data = (from con in project.ProjectDoc
select new
{
CommentCount=project.Comment.Count(x=>x.UserID==con.UserID)
}).ToList();
i think this will help you.