0

I have a complex model, in which I am building a system which has the following model:

Competition
- Id
- Name

Team
- Id
- Name

CompetitionTeam
- Competition
- Team

Player
- Id
- Name
- Age

TeamPlayers
- Team
- Player

Essentially the team can enter many competitions, and can share players in different competitions. I am trying to query from the TeamPlayers table to get the competition in which they are competing for said team:

var players = await _context.Set<TeamPlayer>()
.Include(tp => tp.Player)
.Include(tp => tp.Team)
.ThenInclude(t => t.CompetitionTeam)
.Where(tp.TeamId == teamId && t.CompetitionId == competitionId)
.OrderBy(tp.TeamId)
.ToListAsync(ct);

This is essentially what I want to achieve, but obviously it doesn't run. Can anyone suggest where I am going wrong?

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

is the question to clarify whether the team with specified Id participated in the specified competition? and then if yes to get the list of players who were the part of this team? I understood it only after seeing your code, nice work done! Unfortunately the question doesn't makes it clear
Yeah, not 100% clear but their query was looking for where Team ID and Competition ID matched and implied getting the list of players. So given a competition ID, a check to see if the team is associated, then getting that team's players should suffice. Joining tables like CompetitionTeam or TeamPlayer normally don't need to be first-class entities. (I.e. a DbSet in the DbContext)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.