Reputation: 29
I have five tables which are related like
Chemicals -> Ingredients -> Solutions -> Usages -> Projects
on a SQL-Server, I want to retrieve data Projects that are related to Chemicals, and some data of the intermediate tables. I can do it with the following query (at least in LinqPad):
from c in Chemicals
join i in Ingredients on c.Chem_ID equals i.Chem_ID into TempTab01
from tt01 in TempTab01.DefaultIfEmpty()
join s in Solutions on tt01.Sol_ID equals s.Sol_ID into TempTab02
from tt02 in TempTab02.DefaultIfEmpty()
join u in Usages on tt02.Sol_ID equals u.Sol_ID into TempTab03
from tt03 in TempTab03.DefaultIfEmpty()
join pro in Projects on tt03.Study_ID equals pro.Study_ID into TempTab04
from tt04 in TempTab04.DefaultIfEmpty()
select new
{
c_ChemID = c.Chem_ID,
c_Name = c.Name,
i_ChemID = (int?)tt01.Chem_ID,
i_Sol_id = (int?)tt01.Sol_ID,
i_IngredID = (int?)tt01.Ingred_ID,
tt01.Amount,
s_SolID = (int?)tt02.Sol_ID,
s_SolName = tt02.SolName,
u_SolID = (int?)tt03.Sol_ID,
u_StudyID = (int?)tt03.Study_ID,
pro_StudyID = (int?)tt04.Study_ID,
pro_StudyNo = tt04.StudyNo,
pro_ProjectName = tt04.ProjectName
}
I do not want to use the joins, but Navigation properties instead, but I do not know how to use several Select or SelectMany to drill down to more than 2 tables.
I'm using EF6 to get the data from SQL Server, the edmx-class for Chemicals is e. g.
public long Chem_ID { get; set; }
public string Name { get; set; }
public virtual Person Person { get; set; }
public virtual Project Project { get; set; }
public virtual ICollection<Ingredient> Ingredients { get; set; }
public virtual ICollection<Usage> Usages { get; set; }
that is Chemicals has a 1:m relation to Ingredients, Ingredients to Solutions = 1:1, Solutions to Usages = 1 : m, and Usages to Projects = 1:1. Hope this answers your question.
Upvotes: 1
Views: 63
Reputation: 205599
It would be nice if you have provided the class definitions with navigation properties (one downside of using joins is that the cardinality is not quite clear).
But the principle is simple. For reference type navigation property you use let clause, for collection type - from (optionally appending DefaultIfEmpty()
if left outer join semantics are needed).
So assuming your model is like this:
class Chemical
{
public ICollection<Ingredient> Ingredients { get; set; }
}
class Ingredient
{
public Chemical Chemical { get; set; }
public Solution Solution { get; set; }
}
class Solution
{
public ICollection<Ingredient> Ingredients { get; set; }
public ICollection<Usage> Usages { get; set; }
}
class Usage
{
public Solution Solution { get; set; }
public Project Project { get; set; }
}
class Project
{
public ICollection<Usage> Usages { get; set; }
}
then the query would be like this:
from c in db.Chemicals
from i in c.Ingredients.DefaultIfEmpty()
let s = i.Solution
from u in s.Usages.DefaultIfEmpty()
let p = u.Project
...
Upvotes: 2