views:

81

answers:

1

Hi Folks,

i've got the following code, which compiles but doesn't retrieve the correct results.

I'm trying to retrieve all the Banned log entries for people who have been recorded at cheating on a gaming server.

The database (in this case, two IList tables) has two simple tables.

  • GameFiles : the game which has a log file .. which we parse.
  • LogEntries : an individual entry in a log file. Each game file has mother-bucket load of log entries.

So this is a simple 1 to many relationship.

Currently it's retrieving all the results for GameType.BattleField2, but not for GameType.CallOfDuty4. I have confirmed that the IList gameFiles does contain some data for GameType.BattleField2 and for GameType.CallOfDuty4. I have also confirmed that each of those files has log entries.

So, can someone have a look at this linq and tell me what i've done wrong?

public IList<LogEntry> BannedEntries(GameType? gameType)
{
    var query = from l in _logEntryRepository.GetLogEntries()
                join g in _gamefileRepository.GetGameFiles()
                on l.GameFileId equals g.GameFileId into JoinedResult
                from x in JoinedResult.DefaultIfEmpty()
                select new 
                { 
                    LogEntry = l,
                    GameFile = x
                };

    if (gameType.HasValue)
    {
        query = from q in query
                where q.GameFile.GameType == gameType
                select q;
    }

    // Now retrieve only LogEntries.
    return (from q in query
            where q.LogEntry.EventType == EventType.BannableViolation
            select q.LogEntry)
            .ToListIfNotNullOrEmpty();
}
A: 

Given that you want the logs, try this simplified-for-demo-only code:

string optionalGameType = "COD4";
//retrieve log entries for BANNED, with optional specified game type
List<LogFile> banned = logs.Where(x => x.EventType == "banned")
                 .WhereIf(optionalGameType.Length > 0, (x => x.GameFileID == games.Where(g => g.GameType == optionalGameType).SingleOrDefault().GameFileID))
                 .ToList();           

int cod4BannedCount = banned.Count;

return banned;

I used a string instead of your custom type, and a string instead of your EventType.BannableViolation. It'd be easy for you to use your custom types instead.

The full source/proof is at this pastebin page.

Check out the WhereIf extension method. It's helped me a few times to avoid those conditionals as separate statements.

Given that example, your code might be refactored to look something like this:

List<LogEntry> banned = _logEntryRepository.GetLogEntries()
                .Where(x => x.EventType == EventType.BannableViolation)
                .WhereIf(gameType.HasValue,
                    (x => x.GameFile.GameType == _gamefileRepository.GetGameFiles()
                                         .Where(g => g.GameType == gameType) 
                                         .SingleOrDefault()
                                         .GameType
                     ))
                 .ToList();
p.campbell
hmm. interesting :) I like this WhereIf extension method. Problem with this code is, with this part `.WhereIf(gameType.HasValue, (x => x.GameType == <snip>)) won't/doesn't work .. because `x` is representing a LogEntry .. which doesn't have a property called `GameType` ... that exists on a `GameFile` type.
Pure.Krome
@ PCambell - thanks for the code update. Still doesn't compile. I'm sure it's because the *x => x.<whatever>* represents a logEntry variable .. which doesn't have a reference up to a GameFile..... ?? Maybe a JOIN is required?
Pure.Krome
even though this still didn't work for me, i'll give it a tick cause it was pretty close / good / inspiring :)
Pure.Krome