So you have two tables: Experiment and ExperimentType. There is a many-to-many relation between those two: every Experiment is an experiment of zero or more ExperimentTypes; every ExperimentType is the type of zero or more Experiments.
This many-to-many can be seen in your class definitions. The virtual ICollection<...> on both sides indicates the many-to-many relationship.
In relational databases this many-to-many relation is implemented using a junction table. However, in entity framework you seldom see the junction table. It is in your database, however, you can't access it using your DbContext
But how am I going to perform a join between Experiments and
ExperimentTypes if I can't access the junction table?
Well, Pooh bear should go back to his thinking spot. You don't want to join tables, you want Experiments, each with its ExperimentTypes.
So why not just do the query using the ICollection<...>?
var experiments = myDbContext.Experiments
.Where(experiment => ...) // only if you don't want all experiments
.Select(experiment => new
{ // Select only the properties you actually plan to use
Id = experiment.Id,
Name = experiment.Name,
...
// get all or some of its ExperimentTypes
ExperimentTypes = experiment.ExperimentTypes
.Where(experimentType => ...) // only if you don't want all experiment types
.Select(experimentType => new
{
// again: select only the properties you plan to use
Id = experimentType.Id,
...
})
.ToList(),
});
Entity framework knows the many-to-many, it knows that for this a triple join with the junction table is needed, and will perform this triple join.
Internally this will be a GroupJoin, you'll get Experiments, each with their ExperimentTypes. You even get Experiments that don't have any ExperimentType yet.
If you really want the inner join, you'll have to flatten the Experiments with their ExperimentTypes. This is done using the overload of SelectMany that has a resultSelector as parameter
// flatten the Experiments with their experimentTypes
var flatInnerJoin = myDbContext.Experiments.SelectMany(experiment => experiment.ExperimentTypes,
// from each experiment and one of its experimentTypes make one new object
(experiment, experimentType) => new
{
ExperimentId = experiment.Id,
ExperimentTypeId = experimentType.Id,
...
});
})
Nota bene! This way you won't get the Experiments that have no ExperimentTypes, just as in a standard inner join.