Technology: Rails/ActiveRecord 6.1.x
Ultimately it may be that there is no normal way to do this but here is my goal:
Connect Table 1 via 4 joins to Table 2 where ultimately Table 1 has_many on Table 2. Here is an example:
Table1 = Person ( has many pets )
Join1 = Pet ( belongs to person, has many pet toys )
Join2 = PetToy ( belongs to pet, belongs to toy maker )
Join3 = ToyMaker ( has many pet toys, belongs to investing company )
Join4 = InvestingCompany ( has many toy makers, belongs to ceo )
Table2 = CEO ( has many investing companies )
I want to have something like 'has many :ceos' in 'Person'. But the jump at 'PetToy' is causing me trouble.
I can use 'delegate xyz to abc' to get from an Instance of PetToy with .ceo to return the Table 2 Ceo. And I go from Person all the way to PetToys. But I am unsure how to bridge that gap to get the 'has_many' up a chain of 'belongs_to'.
Is it perhaps impossible?
Table1 = Person ( has many pets )
Join1 = Pet ( belongs to person, has many pet toys )
Join2 = PetToy ( belongs to pet, belongs to toy maker )
Join3 = ToyMaker ( has many pet toys, belongs to investing company )
Join4 = InvestingCompany ( has many toy makers, belongs to ceo )
Table2 = CEO ( has many investing companies )
To get all the CEOs for a person this is the join.
Ceos.joins(companies: { toy_makers: { pet_toys: { pet: :people } } }
.where(people: {id: person.id})
Depending on your needs you could also use has many through.
class Ceo {
has_many :companies
has_many :toy_makers, through: :companies
}
class ToyMaker {
has_many :pet_toys
has_many :people, through: :pet_toys
}
Ceos.joins(toy_makers: { :people }
.where(people: {id: person.id})
Related
Let’s assume I have three tables in my database:
Authors(PK Id, AuthorName)
Books(PK Id, BookName)
Authors_Books(FK BookId, FK AuthorId)
I need to write a method which passes in a parameter int[] authorsIds and returns all books (Id, BookName, list of authors of this book) if it was written by any author whose Id contains in int[] authorsIds parameter.
I need LINQ query (query method).
I really need a help. Appreciate your help very much.
var int[] authors = { 1, 2, 3 };
var books = from book in books
where book.Authors.Any(x => authors.Contains(x.AuthorId))
select book;
PS: I assume book.Authors is your reference to Authors_Books table (or maybe has a different name).
this answer is based on the exact structure without considering that A obj has B in its structure
var book = from b in books
where book.Id in ( from ab in AuthersBooks
where selectedAuthers.contains(ab.AutherId)
select ab.bookId ) //now we have books that are authered by one of the selected authers
select new { BookId = b.Id, // now we create an anonymos object to contain any info we need
BookName = b.Name,
BookAuthers = (from a in authers
join ab in AuthersBooks
on a.Id == ab.AuthersId
where ab.bookid == b.Id
select a)
this will propably have syntax errors and after correcting you may get an error about multiple threads which already has an answer here
I guess there must be an easy way, but not finding it. I would like to check whether a list of items, appear (completely or partially) in another list.
For example: Let's say I have people in a department as List 1. Then I have a list of sports with a list of participants in that sport.
Now I want to count, in how many sports does all the people of a department appear.
(I know some tables might not make sense when looking at it from a normalisation angle, but it is easier this way than to try and explain my real tables)
So I have something like this:
var peopleInDepartment = from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList()
};
var peopleInTeam = from s in Sports
select new
{
SportID = s.SportID,
PeopleInSport = s.Participants.Select(x => x.PersonID),
NoOfMatches = peopleInDepartment.Contains(s.Participants.Select(x => x.PersonID)).Count()
};
The error here is that peopleInDepartment does not contain a definition for 'Contains'. Think I'm just in need of a new angle to look at this.
As the end result I would like print:
Department 1 : The Department participates in 3 sports
Department 2 : The Department participates in 0 sports
etc.
Judging from the expected result, you should base the query on Department table like the first query. Maybe just include the sports count in the first query like so :
var peopleInDepartment =
from d in Department_Members
group d by r.DepartmentID into g
select new
{
DepartmentID = g.Key,
TeamMembers = g.Select(r => d.PersonID).ToList(),
NumberOfSports = Sports.Count(s => s.Participants
.Any(p => g.Select(r => r.PersonID)
.Contains(p.PersonID)
)
)
};
NumberOfSports should contains count of sports, where any of its participant is listed as member of current department (g.Select(r => r.PersonID).Contains(p.PersonID))).
Lets say I have a class as follows:
case class Person(
name:String,
age:Int,
dependents:List[Person]
)
Lets say I have the following four people:
val p1 = Person("Tom",50,List(p2,p4))
val p2 = Person("Bob",20,List(p3))
val p3 = Person("Jimmy",25,List(p4))
val p4 = Person("Harry",11,Nil)
My people list is val pList = List(p1,p2,p3,p4)
I want to filter this collection to get all the people who have an 11 year old dependent.
What is one way to do it?
The algorithm can be summed up as For each dependent(d) of each person(p) in pList, if age of dependant(d) is == 11, collect the person(p).
How do I express it in scala?
Take the list of persons, and use the filter method on it, checking if each dependent contains a person whose age is 11.
pList.filter(_.dependents.exists(_.age == 11))
This will only check 1 layer deep obviously, so in your example, it will return Tom and Jimmy, because they are the only Persons with a direct dependent who is 11 years old:
Person(
Tom,
50,
List(Person(Bob,20,List(Person(Jimmy,25,List(Person(Harry,11,List()))))), Person(Harry,11,List()))
)
Person(
Jimmy,
25,
List(Person(Harry,11,List()))
)
Alternatively you could make it a little more generic like so:
def dependentAged(age: Int)(person: Person) = person.dependents.exists(_.age == age)
val filtered = pList.filter(dependentAged(11))
Your description of the algorithm translates very well to a for comprehension in scala.
For each dependent(d) of each person(p) in pList, if age of
dependant(d) is == 11, collect the person(p)
We iterate through pList and create a new variable person at each iteration. If the dependents of the person meet the guard criteria, we yield that person from pList. i.e. if person.dependents.exists(dependent => dependent.age == 11)
With for and yield:
for(person <- pList if person.dependents.exists(dependent => dependent.age == 11)) yield person
This gives a list of two people:
List[Person] = List(
Person(Tom,50,List(Person(Bob,20,List(Person(Jimmy,25,List(Person(Harry,11,List()))))),
Person(Harry,11,List()))), Person(Jimmy,25,List(Person(Harry,11,List())))
)
var companytoexclude = from c in db.Companies
from p in c.Projects
where p.ProjectEndDate == null
select c;
var list = from m in db.Members.Include("Companies.Projects.Experiences")
where m.MemberId == id
select m;
how do I exclude companies that are in companytoexclude in list?
Member have many company
company have many project
project have many experiences
K I kind of solved it.
So what I did is just add in
foreach (Company c in companytoexclude )
{
list .First().Companies.Remove(c);
}
so is there a easier to show this?
I want the member with list of companies, not just companies.
some data
Member
MemberId Name
2011 Jet
Company
CompanyId MemberId CompanyName
18 2011 Company1
29 2011 Company2
ProjectId CompanyId ProjectName ProjectEndDate
1 29 Project1 2008-08-01 00:00:00.000
2 29 Project2 2009-08-01 00:00:00.000
3 18 Project3 NULL
now I want it to return everything but company1 and project3
How about:
var list = from m in db.Members.Include("Companies.Projects.Experiences")
where m.MemberId == id
where !m.Companies.Intersect(companiesToExclude).Any()
select m;
That will only return members which don't include any companies which you're trying to exclude.
Mind you, given that you're specifying a MemberId, I'd pretty much only expect one result anyway... it's unclear what you're trying to do.
If you want all the companies from that single member except the companies to exclude, it's easy:
var member = db.Members.Include("Companies.Projects.Experiences")
.Single(m => m.MemberId == id);
var companies = member.Companies.Except(companiesToExclude);
If that's not what you're after, please clarify your question.
Also note that your companiesToExclude query may well not be right to start with. Are you trying to exclude all companies with any project with a null end date? If so, you want:
var companiesToExclude = db.Companies
.Where(c => c.Projects
.Any(p => p.ProjectEndDate == null))
I have a table called Payroll. Payroll can have many PayStubs. In other words there is table called PayStub that is a child entity of Payroll. PayStub has a child Entity called PayrollTax. I want to write a LINQ-to-SQL query that gets all payrolls which have more than one Payroll Tax. I use the following query:
public IList<Payroll> GetPayrollsWithPayrollTaxes()
{
return (from payroll in ActiveContext.Payrolls
join payStub in ActiveContext.PayStubs on payroll.PayrollID equals payStub.PayrollID
where payStub.InternalPayrollTaxes.Count > 0
select payroll
).ToList();
}
The problem is since there is a one to many relationship between Payroll and PayStub, I end up getting the same Payroll twice. I want a unique list of Payrolls.
Any ideas and suggestions are appreciated!
I think using Any (EXISTS in SQL) might help you here.
public IList<Payroll> GetPayrollsWithPayrollTaxes()
{
return (from payroll in ActiveContext.Payrolls
where ActiveContextPayStubs.Any(payStub =>
payroll.PayrollID == payStub.PayrollID &&
payStub.InternalPayrollTaxes.Any())
select payroll
).ToList();
}
Have you tried .Distinct().ToList() ?
Or you could add an into after the join like this:
(from payroll in ActiveContext.Payrolls
join payStub in ActiveContext.PayStubs on payroll.PayrollID equals payStub.PayrollID into payStubGroup
where payStubGroup.Any(p => p.InternalPayrollTaxes.Any())
select payroll
).ToList();