Loading related entities multiple branches and multiple levels - c#

I'm writing an application where I need the EvaluationRounds with a particular student.
Everything starts with the project. A project has many groups. A group has many members, but one member can also be in many groups. This is done by the associative table ProjectGroupMembers On the other hand, a project has many evaluation rounds.
Currently I have this linq statement:
from r in _context.EvaluationRounds.Include(e => e.EvaluationRoundProject.ProjectGroups.Select(pg => pg.Persons))
.Include(e => e.Evaluations)
join g in _context.ProjectGroups on r.ProjectId equals g.ProjectId
join m in _context.ProjectGroupMembers on g.ProjectGroupId equals m.GroupId
where m.PersonId == studentId && r.EvaluationRoundStartTime < DateTime.Now && r.EvaluationRoundEndTime > DateTime.Now
select r
We use the using statement to dispose of the dbcontext as soon as we have the list.
The problem is that the EvaluationRoundProject and its relatives are not loaded with the EvaluationRounds. This is what we get:
'((System.Data.Entity.DynamicProxies.EvaluationRound_7400F2ED13550F1E92655A802808E4B94D454A30979C80D0EEED31D0CB7D7005)(new System.Collections.Generic.Mscorlib_CollectionDebugView(activeEvaluationrounds).Items[0])).EvaluationRoundProject'
threw an exception of type 'System.ObjectDisposedException'
I have tried:
from r in _context.EvaluationRounds.Include("EvaluationRoundProject").Include(e => e.EvaluationRoundProject.ProjectGroups.Select(pg => pg.Persons)).Include(e => e.Evaluations)
join g in _context.ProjectGroups on r.ProjectId equals g.ProjectId
join m in _context.ProjectGroupMembers on g.ProjectGroupId equals m.GroupId
where m.PersonId == studentId && r.EvaluationRoundStartTime < DateTime.Now && r.EvaluationRoundEndTime > DateTime.Now
select r
and also
from r in _context.EvaluationRounds.Include(a => a.EvaluationRoundProject).Include(e => e.EvaluationRoundProject.ProjectGroups.Select(pg => pg.Persons)).Include(e => e.Evaluations)
join g in _context.ProjectGroups on r.ProjectId equals g.ProjectId
join m in _context.ProjectGroupMembers on g.ProjectGroupId equals m.GroupId
where m.PersonId == studentId && r.EvaluationRoundStartTime < DateTime.Now && r.EvaluationRoundEndTime > DateTime.Now
select r
Edit: The evaluations also do not load into the evaluationround
Edit2: this is the whole using code
using (_context = new PeerEvaluationContext())
{
var activeEvaluationrounds = from r in _context.EvaluationRounds.Include(e => e.EvaluationRoundProject.ProjectGroups.Select(pg => pg.Persons)).Include(e => e.Evaluations)
join g in _context.ProjectGroups on r.ProjectId equals g.ProjectId
join m in _context.ProjectGroupMembers on g.ProjectGroupId equals m.GroupId
where m.PersonId == studentId && r.EvaluationRoundStartTime < DateTime.Now && r.EvaluationRoundEndTime > DateTime.Now
select r;
return activeEvaluationrounds.ToList();
}
Edit 3: this problem occurs because lazy loading is used. But I went looking on the internet and they said the include part would take care of this.

I suspected that the error occured because of lazy loading. EvaluationRound or EvaluationRoundProject entities have navigation properties which is virtual and EF is attempting to load data in somewhere after _context already disposed. So, would you try to use another class to select query;
var activeEvaluationrounds = from r in _context.EvaluationRounds.Include(e => e.EvaluationRoundProject.ProjectGroups.Select(pg => pg.Persons)).Include(e => e.Evaluations)
join g in _context.ProjectGroups on r.ProjectId equals g.ProjectId
join m in _context.ProjectGroupMembers on g.ProjectGroupId equals m.GroupId
where m.PersonId == studentId && r.EvaluationRoundStartTime < DateTime.Now && r.EvaluationRoundEndTime > DateTime.Now
select new EvaluationRoundDto
{
EvaluationRoundId = r.EvaluationRoundId,
ProjectId = r.ProjectId
//etc.
};
I think you should check virtual navigation properties and where are they used after context already disposed.

Related

navigation property vs using left join

I have this linq statement where I want to convert into navigation property. The linq statement has a left join so I am not sure how to do that with the navigation property. I am using EF 6.0.0.0. I am trying to get all the MeetingPollingResponseTexts if there is values or nulls.
MeetingPollingParticipantsAnswers = (from p in db.MeetingPollingParticipants
join mp in db.MeetingPollings on p.MeetingPollingId equals mp.MeetingPollingId
join pq in db.MeetingPollingQuestions on mp.MeetingPollingId equals pq.MeetingPollingId
join pp in db.MeetingPollingParts on pq.MeetingPollingQuestionId equals pp.MeetingPollingQuestionId
join pv in db.MeetingPollingPartsValues on pp.MeetingPollingPartsId equals pv.MeetingPollingPartsId
join rt in db.MeetingPollingResponseTexts on pv.MeetingPollingPartsValuesId equals rt.MeetingPollingPartsValuesId into lj_rt
from rt in lj_rt.DefaultIfEmpty()
where p.MeetingPollingId == MeetingPollingId && p.CustomerId == CustomerId
select new Model.MeetingPollingParticipantsAnswers
{
QuestionValue = pv.QuestionValue,
MeetingPollingQuestionResponseText = rt.MeetingPollingQuestionResponseText,
}).ToList();
var meetingParticipantsAnswers = db.MeetingPollingParticipants
.Include(x => x.MeetingPolling)
.Include(x => x.MeetingPollingQuestions
.Select(q => q.MeetingPollingParts
.Select(i => i.MeetingPollingPartsValues)))
.Where(p => p.CustomerId == CustomerId && p.MeetingPollingId == MeetingPollingId).ToList();

How to call a method within .Select in Linq query without having to write select twice?

The following is my code that works. But as you can see I am having to write select twice
var lstCargoRequestVM =
(from c in db.Cargo
join v in db.Vehicles on c.VehicleID equals v.VehicleID
join cmp in db.Companies on c.CompanyID equals cmp.CompanyID
where c.Isdeleted == false && c.IsActive == true
select new CargoRequestVM
{
CargoId = c.CargoID,
CompanyName = cmp.CompanyName,
VehicleNo = v.VehicleNo,
Date = c.DateOfPassage,
Type = c.Type.ToString()
})
.AsEnumerable()
.Select(x => new CargoRequestVM
{
CargoId = x.CargoId,
CompanyName = x.CompanyName,
VehicleNo = x.VehicleNo,
Date = x.Date,
Type = CargoElements.CargoTypeName(x.Type.ToString())
}).ToList();
Is it possible to do the same without having to write select twice? There could be more than a dozen properties in certain case. I don't want to make my code unnecessarily lengthy.
Probably that wouldn't have a translation to underlying database and thus you need to write basically twice. However you can apply the AsEnumerable() after where using method syntax like (assuming you in fact have a good relational schema defined and navigational properties set - in Linq you very rarely need join keyword):
stVM = db.Cargo
.Include( c => c.Vehicle )
.Include( c => c.Company )
.Where( c => !c.Isdeleted && c.IsActive )
.AsEnumerable()
.Select( c => new CargoRequestVM
{
CargoId = c.CargoID,
CompanyName = c.Company.CompanyName,
VehicleNo = c.Vehicle.VehicleNo,
Date = c.DateOfPassage,
Type = CargoElements.CargoTypeName(c.Type.ToString())
}).ToList();

How to do this query using expression in LINQ?

select t.*
from Task t
inner join Project p on a.ProjectId = t.ProjectId
where p.ProjectTypeId IN ( select ptg.ProjectTypeId
from UserGroup ug
inner join ProjectTypeGroup ptg on ug.GroupId = ptg.GroupId
where ug.UserId = 1 -- MUTABLE VALUE
)
In the attempt query given by you, I don't see Task being used.
Since there is no relation between your sub-query and your main query, you should split them in to two queries:
var projTypeIds = (from ug in UserGroup
join ptg in ProjectTypGroup on ug.GroupId equals ptg.GroupId
where ug.UserId == 1
select ptg.ProjectTypeId).ToList()
Once you have your output, check for .Contains
var task = (from t in Task
join p in Project on p.ProjectId equals t.ProjectId
where projTypeIds.Contains(p.ProjectTypeId)
select t).FirstOrDefault();
I assume you need only one object from this query hence used .FirstOrDefault(), if you are expecting a list using .ToList()
You can use this.
from t in Task
join p in Project
on t.ProjectId equals p.ProjectId
let subQ = ( from ug in UserGroup
join ptg in ProjectTypeGroup
on ug.GroupId equals ptg.GroupId
where ug.UserId == 1
select ptg.ProjectTypeId)
where subQ.Contains(p.ProjectTypeId)
select t
or you can use this.
int loggedUserId = 1;
var _userGroups =
UserGroup.Join(ProjectTypeGroup,
t => t.GroupId, p => p.GroupId,
(t, p) => new {t, p})
.Where(n => n.t.UserId == loggedUserId)
.Select(s => s.p.ProjectTypeId);
var projectTypeIds =
Task.Join(Project,
t => t.ProjectId, p => p.ProjectId,
(t, p) => new {t, p})
.Where(n => _userGroups.Contains(n.p.ProjectTypeId) )
.Select(n => n.t);
projectTypeIds.ToList();

inner join query in asp.net MVC4

I write query about search about specific employee but did'nt work ,I know there is an error in my query but did'nt now where it.
I have 2 tables one for company and another for employee info.
the progress will be:
1'st Query search in company table by department number and company
number then get the PK_companyID .
2'ed JOIN company.PK_companyID==employee.FK_companyID.
3'ed Query will search in employee table by FK_companyID when the
name enter will be the same in employee table.
I hope its Clear to understand
var query = (from c in db.Company
where c.departmentNO== departmentNumber && c.companyNo==companyNumber
join x in db.Employee c.PK_companyID==x.FK_companyID
where (x.FirstName.Contains(firstName ?? x.FirstName)
&& x.SecondName.Contains(secondName ?? x.SecondName)
&& x.ThirdName.Contains(thirdName ?? x.ThirdName)
&& x.FourthName.Contains(fourthName ?? x.FourthName))
select x).ToList();
Thank in advance.
You can simplify your query and your filtering by using code such below, should also result much cleaner SQL if you are not using all your filters.
var employees = (from c in db.Company
join e in db.Employee on c.PK_companyID equals e.FK_companyID
where c.departmentNO == departmentNumber && c.companyNo == companyNumber
select e);
if (!String.IsNullOrEmpty(firstName))
employees = employees.Where(pr => pr.FirstName.Contains(firstName));
if (!String.IsNullOrEmpty(secondName))
employees = employees.Where(pr => pr.SecondName.Contains(secondName));
if (!String.IsNullOrEmpty(thirdName))
employees = employees.Where(pr => pr.ThirdName.Contains(thirdName));
if (!String.IsNullOrEmpty(fourthName))
employees = employees.Where(pr => pr.FourthName.Contains(fourthName));
return employees.ToList();
var query = (from c in db.Company
join x in db.Employee c.PK_companyID == x.FK_companyID
where c.departmentNO == departmentNumber && c.companyNo == companyNumber
&& (x.FirstName.Contains(firstName ?? x.FirstName)
&& x.SecondName.Contains(secondName ?? x.SecondName)
&& x.ThirdName.Contains(thirdName ?? x.ThirdName)
&& x.FourthName.Contains(fourthName ?? x.FourthName))
select x).ToList();
You should use keyword "equals" instead of "==" in join as below:
var query = (from c in db.Company
join x in db.Employee c.PK_companyID equals x.FK_companyID
where c.departmentNO == departmentNumber && c.companyNo == companyNumber
.......
Hope this will work.

LINQ syntax and the where clause

I have written some LINQ but it doesn't return the correct data, it seems to ignore my where clause. Can anybody advise me on what I am doing wrong with the syntax?
IEnumerable<Ranking> lst = (from r in results
join m in membersToRank on r.UserId equals m.userId
join t in teamsToRank on m.teamId equals t.teamId
where r.ResultDate >= rankingStart
&& r.ResultDate <= rankingEnd
select new Ranking
{
memberId = m.memberId,
chain = t.chain,
name = m.name,
teamId = m.teamId,
value = results.Count(i => i.IsCorrect && i.UserId == m.userId)
}).ToList();
This line
value = results.Count(i => i.IsCorrect && i.UserId == m.userId)
will bypass the where clause. You have have to repeat the where there
value = results.Where(...).Count(i => i.IsCorrect && i.UserId == m.userId)
or
var results2 = results.Where(...)
and then use only results2.
(as a sidenote, it will even bypass the join, so it could become a little more complex depending on what you want)

Categories

Resources