Many to many relationships are typically cases where you will want navigation properties on both sides.
For instance:
public class Competition
{
// ...
public virtual ICollection<CompetitionTeam> CompetitionTeams { get; set; } = new List<CompetitionTeam>();
}
public class Team
{
// ...
public virtual ICollection<CompetitionTeam> CompetitionTeams { get; set; } = new List<CompetitionTeam>();
public virtual ICollection<TeamPlayer> TeamPlayers { get; set; } = new List<TeamPlayer>();
}
public class CompetitionTeam
{
public virtual Competition Competition { get; set; }
public virtual Team Team { get; set; }
}
public class Player
{
// ...
public virtual ICollection<TeamPlayer> TeamPlayers { get; set; } = new List<TeamPlayer>();
}
public class TeamPlayer
{
public virtual Team Team { get; set; }
public virtual Player Player { get; set;}
}
From there you can get the players through the relationships.
Now in your example if you have the Team ID you really just need to select the players in that team, and assert that the team was actually in the competition:
bool teamWasInCompetition = context.Competitions
.Any(c => c.CompetitionId == competitionId
&& c.CompetionTeams.Any(t => t.TeamId == teamId));
IList<Player> players = teamWasInComeption
? context.Teams.Where(t => t.TeamId == teamId).SelectMany(t => t.Players.Select(p => p.Player)).ToList()
: new List<Player>();
The first statement asserts that the Team actually took part in the competition. If it didn't, the second statement to get players returns an empty list. Otherwise, the second statement finds the Team by ID and then selects the players through the Team.TeamPlayers collection.
If you need those players to include other relationships you can add .Include() statements, or better, project the properties into a view model or such using .Select(). Note that with EF you do not need to explicitly use .Include() like a JOIN in SQL in order to reference related entities in a Linq query, only if you actually want to pre-fetch that data (eager load) in the returned entities.