I am newbie @ LINQ and trying my best. I know how to pull and join these tables in a one-to-one relationship, but I am stuck trying to implement this, with a better approach:
But now I have no idea how to get the Player and Scores but from a specific Datetime in the Game table. I am using: .NET Framework 4.7.2 and Entity Framework 6.4.4 , and working with Code First approach.
EDIT: I normally join them on the matching Datetime timestamp .
EDIT #2: My attempt: ....=> t ->
is some input to this function
, below is the body
:
var data = (from game in db.Games
join p in db.Players on game.Players equals p
join s in db.Scores on p equals s.Player
where
(
game.timestamp.Hour == t.Hour &&
game.timestamp.Minute == t.Minute &&
game.timestamp.Second == t.Second
)
select new { s, p }).ToList<Object>();
EDIT #3: Trying to get this into List<Object>()
.
EDIT #4: When I try to loop over the data, after returning it, using the Query sample from @Svyatoslav Danyliv's answer, I get this:
My tables:
using System;
using System.Collections.Generic;
namespace Sample
{
////////////////////////////////////////
//
// Game and Player have a one-to-many relationship
// Scores and Player have a one-to-one relationship
//
public class Player
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int PlayerID { get; set; }
[MaxLength(200)]
public string Name { get; set; }
[DataType(DataType.DateTime)]
public DateTime Created { get; set; };
}
public class Scores
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ScoreID { get; set; }
public int Wins { get; set; } = 0;
public int Lost { get; set; } = 0;
public int TimesPlayed { get; set; } = 0;
[Required]
public virtual Player Player { get; set; }
[DataType(DataType.DateTime)]
public DateTime timestamp { get; set; };
}
public class Game
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
public DateTime timestamp { get; set; };
public virtual ICollection<Player> Players { get; set; } = new List<Player>();
}
}
You appear to be missing a navigation property from Player to Score, which also seems like an odd design, since I would normally assume that a player could play multiple games, and hence could have multiple scores. However, if you add the missing navigation property, then should work:
var data = db.Games
.Include(g=>g.Players)
.Include(g=>g.Players.Select(p=>p.Scores)) // EF 6.x
//.ThenInclude(p=>p.Scores) // EF Core
.Where(g=>g.timestamp.Hour == t.Hour)
.Where(g=>g.timestamp.Minute == t.Minute)
.Where(g=>g.timestamp.Second == t.Second)
.ToList();
There is probably a much better way of handling your game timestamp as well using DbFunctions or EntityFunctions like from here: Linq To Sql compare Time only
If you wanted this flattened, then project using SelectMany:
var data = db.Games
.Include(g=>g.Players)
.Include(g=>g.Players.Select(p=>p.Scores)) // EF 6.x
//.ThenInclude(p=>p.Scores) // EF Core
.Where(g=>g.timestamp.Hour == t.Hour)
.Where(g=>g.timestamp.Minute == t.Minute)
.Where(g=>g.timestamp.Second == t.Second)
.SelectMany(g=>g.Players)
.ToList();
Something like that, but I think you have to apply appropriate filter on Score's timestamp
var query =
from game in db.Games
where
(
game.timestamp.Hour == t.Hour &&
game.timestamp.Minute == t.Minute &&
game.timestamp.Second == t.Second
)
select new
{
Game = game,
Players = game.Players.Select(p => new
{
Player = p,
Scores = db.Scores.Where(s = s.Player == p).ToArray()
}).ToArray()
}
var result = query.ToList();
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.