Problem with a Linq to Entity query that contains a passed list of entities - linq

I have two entities
User { UserID, Name, UserTypeID }
StudentParent { StudentParentID, StudentID, ParentID }
// where
UserTypeID { 1=student, 2=parent }
Both StudentParent.StudentID and StudentParent.ParentID are foreign keys pointing to User.UserID
I have a list of Students (IEnumerable<User>) that I need to get the list of parents for. I need help figuring out the proper expression to get the list of parents.
Should I be using a contains or any statement to match against the list of Student Users?

You should be able to Select the Parent entites from your IEnumerable of students.
students.SelectMany(s => s.StudentParents.Select(sp => sp.ntParent_Parent));
This performs a projection from your collection of students, not all Students.
Logically it is something like
here's a set of students
for each of those students, get the student parent entities
for each of those studentparent entities, get the parent
It also may be more useful to select into an anonymous type so you can see which parents belong to which students.
students.Select(s => new {
Student = s,
Parents = s.StudentParents.Select(sp => sp.ntParent_Parent))});

Related

Loopback4 filter inside the scope return list still

I'm using lb4
I have some problems here, I try to find the list with where conditions inside the scope with pagination.
const teacherWithStudents = await this.teacherRepository.find({limit:10,skip:0,
include: [{
relation: "student",
scope: {
where: { "name": "some random name here" },
}
}]
})
The expected teacher's array is : [] (because I searched a random string in student name which is not in DB)
but I got teachers to array without student like this: [{teacherId:1,teacherName:"Stella"}{teacherId:2,teacherName:"Mery"}]
if I filter student names if no teacher has a student that I filtered I need an empty array but I get only a teacher.
I hope I explained the issue in detail.
Thanks in advance
This is expected as the parent and relation queries should be perceived as two separate queries.
First, the list of teachers based on the parent query are resolved. The IDs of the resolved teachers are then used as a constraint when querying for the list of students.
Both results are then combined together to create the final response.
Loopback uses left join. if you want to find only teachers where student is not null then you have to use inner join with native query.

Laravel/Eloquent get all appointments from a polymorphic "member_id" through a appointment_members table

I have an appointments table and an appointment_members table and my users need to be able to get a collection of appointments by searching with a "member_id", which could be a Person, Incident or CustomerID. The appointment_members table has member_id and appointment_id columns, so the member_type (also a column) is irrelevant. This all set up by a previous dev and what is missing are the relationships on the Eloquent models. I'm just creating a simple GET route that needs to return any/all appointments by that member_id. Each row has one appointment, so if I were to pass in a member_id that returned 10 results, some could have appts and others not, but at the end of the day I just need a collection of appts that are related to that member_id. Here's a screenshot of the appointment_members table:
If I create a simple hasOne relationship to appointments on appointment_members:
public function appointments()
{
return $this->HasOne(Appointment::class, 'id', 'appointment_id');
}
I can get a collection of appointment_members with it's respective appointment, but not sure how I boil it down to just getting the appointments. One workaround I have is to use that HasOne and then pluck/filter the appointments:
$appointmentMembers = AppointmentMembers::where('member_id', $request->input('memberId'))->get();
$appointments = $appointmentMembers->pluck('appointments')->filter();
Curious if anyone might see a better way to go about this. Thanks!
I'm possibly not understanding, but I would probably take the simplest approach here if the member type is not important.
The table is already set up to handle either a belongsToMany or a morphMany, so create the relationship on the Member class (or if you don't have a parent member class, stick it on each of the types Person, Incident, etc. You can also do this via poly, of course, but this is a simple example to get what you need):
public function appointments()
{
return $this->belongsToMany(Appointment::class)->withPivot('member_type');
}
And then just query on the member object you need appointments for (having poly would make this one step):
$allAppointmentsForID = $member->appointments();
$appointments = $allAppointmentsForID->wherePivot('member_type', $whateverClassThisIS);
The above takes member_type into account. If this doesn't matter, you can just use the top line.
Your original db is setup to handle polymorphic relations, so if you wanted more than the appointment you can set it up this way as well. For now, you'll need to add the TYPE to the query to cover the different classes.
If the member type is important, polymorphic might be something like this on the Member class:
public function appointments()
{
return $this->morphMany(Appointment::class, 'memberableOrmember_typeOrWhatever');
}
Then you can query on the member object with just one line
$appointments = $member->appointments();

Imroving/Modifying LINQ query

I already have a variable containing some groups. I generated that using the following LINQ query:
var historyGroups = from payee in list
group payee by payee.Payee.Name into groups
orderby groups.Key
select new {PayeeName = groups.Key, List = groups };
Now my historyGroups variable can contain many groups. Each of those groups has a key which is a string and Results View is sorted according to that. Now inside each of those groups there is a List corresponding to the key. Inside that List there are elements and each one those element is an object of a particular type. One of it's fields is of type System.DateTime. I want to sort this internal List by date.
Can anyone help with this? May be modify the above query or a new query on variable historyGroups.
Thanks
It is not clear to me what you want to sort on (the payee type definition is missing as well)
var historyGroups = from payee in list
group payee by payee.Payee.Name into groups
orderby groups.Key
select new {
PayeeName = groups.Key,
List = groups.OrderBy(payee2 => payee2.SomeDateTimeField)
};
Is most straightforward.
If you really want to sort only by date (and not time), use SomeDateTimeField.Date.
Inside that List there are elements and each one those element is an object of a particular type. One of it's fields is of type System.DateTime
This leads me to maybe(?) suspect
List = groups.OrderBy(payee2 => payee2.ParticularTypedElement.DateTimeField)
Or perhaps even
List = groups.OrderBy(payee2 => payee2.ObjectsOfParticularType
.OfType<DateTime>()
.FirstOrDefault()
)
I hope next time you can clarfy the question a bit better, so we don't have to guess that much (and come up with a confusing answer)

Can LINQ ToArray return a strongly-typed array in this example?

I've contrived this example because it's an easily digested version of the actual problem I'm trying to solve. Here are the classes and their relationships.
First we have a Country class that contains a Dictionary of State objects indexed by a string (their name or abbreviation for example). The contents of the State class are irrelevant:
class Country
{
Dictionary<string, State> states;
}
class State { ... }
We also have a Company class which contains a Dictionary of zero or more BranchOffice objects also indexed by state names or abbreviations.
class Company
{
Dictionary<string, BranchOffice> branches;
}
class BranchOffice { ... }
The instances we're working with are one Country object and an array of Company objects:
Country usa;
Company companies[];
What I want is an array of the State objects which contain a branch. The LINQ I wrote is below. First it grabs all the companies which actually contain a branch, then joins to the list of states by comparing the keys of both lists.
The problem is that ToArray returns an anonymous type. I understand why anonymous types can't be cast to strong types. I'm trying to figure out whether I could change something to get back a strongly typed array. (And I'm open to suggestions about better ways to write the LINQ overall.)
I've tried casting to BranchOffice all over the place (up front, at list2, at the final select, and other less-likely candidates).
BranchOffice[] offices =
(from cm in companies
where cm.branches.Count > 0
select new {
list2 =
(from br in cm.branches
join st in usa.states on br.Key equals st.Key
select st.Value
)
}
).ToArray();
You can do:
select new MyClassOfSomeType {
..
)
For selection, you can give it a custom class type. You can also then use ToList. With ArrayList, if you need to keep it loosely typed, you can then make it strongly typed later using Cast<>, though only for any select result that doesn't generate an anonymous class.
HTH.
If i understand the problem correctly, the you want just the states that have office brances in them, not the branches too. If so, one posible linq is the following:
State[] offices =
(from cm in companies
where cm.branches.Count > 0
from br in cm.branches
join st in usa.states on br.Key equals st.Key
select st.Value
).Distinct().ToArray();
If you want both the states and the branches, then you will have to do a group by, and the result will be an IEnumerable>, which you can process after.
var statesAndBranches =
from cm in companies
where cm.branches.Count > 0
from br in cm.branches
join st in usa.states on br.Key equals st.Key
group br.Value by st.Value into g
select g;
Just one more thing, even though you have countries and branches declared as dictionaries, they are used as IEnumerable (from keyValuePair in dictionary) so you will not get any perf benefit form them.

Concatenating lists inside a LINQ query

My data structure is set up this way
A user takes a number of modules
A module contains a number of courses
Here's how the relationship looks like:
How do I get a list of courses the user takes?
The query I have now is:
var courses = (from ClassEnrollment enrolment in entities.ClassEnrollment
where enrolment.UserID == UserID
join Module module in entities.Module
on enrolment.ModuleID equals module.ID
select module.Course
).ToList();
However, this doesn't result in a list of courses, but rather a list of list of courses.
How can I flatten this query to a list of distinct courses?
According to your data structure screenshot, you have a one-to-many relationship between the ClassEnrollment and Module, as well as navigational property called Module. You also have a many-to-many relationship between Module and Course, but the navigational property should be called Courses. Given your code, you want something like this:
var courses = entities.
ClassEnrollment.
Where(e => e.UserID == UserID).
SelectMany(e => e.Module.Courses).
ToList();
Your question, however, mentions a user: A user takes a number of modules, How do I get a list of courses the user takes?. I don't see any User entity anywhere else, though, so it would be nice if you could clarify. Are you using LINQ-to-SQL, btw?
Something like this:
var courses = from ClassEnrollment enrolment in entities.ClassEnrollment
from module in entities.Module
where enrolment.ModuleID equals module.ID && enrolment.UserID equals UserID
select module.Course
Use SelectMany.
You can use
courses.SelectMany(c => c);
In your query you don't need explicitly specify the type for the range variables
Or you can join course to the query
var query = from enrolment in entities.ClassEnrollment
join module in entities.Module on enrolment.ModuleID equals module.ID
join course in entities.Course on module.CourseID equals course.ID
where enrolment.UserID == UserID
select course;
var course = query.ToList();

Resources