Requête Linq où First () semble returnner une valeur nulle lorsque les résultats ne sont pas trouvés

On m'a présenté ce qui suit (cela a été simplifié pour la question):

int programId = 3; int refugeeId = 5; var q = ( from st in Students join cr in Class_Rosters on st.StudentId equals cr.StudentId join pp in Student_Program_Part on cr.StudentId equals pp.StudentId from refg in (Student_Program_Participation_Values .Where(rudf => rudf.ProgramParticipationId == pp.ProgramParticipationId && rudf.UDFId == refugeeId)).DefaultIfEmpty() where cr.ClassId == 22898 && pp.ProgramId == programId select new { StudentId = st.StudentId, Refugees = refg.Value ?? "IT WAS NULL", Refugee = Student_Program_Participation_Values .Where(rudf => rudf.ProgramParticipationId == pp.ProgramParticipationId && rudf.RefugeeId == refugeeId) .Select(rudf => (rudf.Value == null ? "IT WAS NULL" : "NOT NULL!")) .First() ?? "First Returned NULL!", }); q.Dump(); 

Dans la requête ci-dessus, la table Student_Program_Participation_Values ​​n'a pas d'loggings pour tous les élèves. La valeur Refugees renvoie correctement la valeur ou "IT WAS NULL" lorsqu'il existe un logging manquant dans Student_Program_Participation_Values. Cependant, la colonne Refugee renvoie "NOT NULL!" ou "First Returned NULL!".

Ma question est, pourquoi est "First Returned NULL!" étant donné que, d'après mon expérience avec Linq, appeler First () sur un set vide devrait lever une exception, mais dans cette requête, il semble faire quelque chose de complètement différent. Notez que refg.Value n'est jamais nul dans la database (c'est une valeur valide, ou il n'y a pas d'logging).

Notez également qu'il s'agit de Linq to SQL et que nous exécutons cette requête dans Linqpad.

Pour clarifier, voici quelques exemples de résultats:

 Réfugié réfugié
 22122 Vrai NON NUL!
 2332 C'ETAIT NULL Premier rendu NULL!

Dans ce qui précède, lorsque Refugees renvoie "IT WAS NULL", il n'y avait aucun logging dans la table Student_Program_Participation_Values, donc je m'attendais à ce que First () lève une exception, mais à la place elle était nulle, donc Refugee affiche "First Returned NULL!"

Des idées?

Mise à jour: L'énigmativité m'a poussé dans la bonne direction en soulignant que j'étais bloqué sur l'appel First () quand être un IQueryable the First () n'était pas vraiment un appel de fonction, mais simplement traduit en "TOP 1" dans le question. C'était évident quand j'ai regardé le SQL généré dans LINQPad. Voici la partie importante du SQL généré qui permet de comprendre ce qui se passe et pourquoi. Je ne vais pas coller le tout car c'est énorme et pas pertinent pour la discussion.

 ... COALESCE(( SELECT TOP (1) [t12].[value] FROM ( SELECT (CASE WHEN 0 = 1 THEN 'IT WAS NULL' ELSE CONVERT(NVarChar(11), 'NOT NULL!') END) AS [value], [t11].[ProgramParticipationId], [t11].[UDFId] FROM [p_Student_Program_Participation_UDF_Values] AS [t11] ) AS [t12] WHERE ([t12].[ProgramParticipationId] = [t3].[ProgramParticipationId]) AND ([t12].[UDFId] = @p8) ), 'First Returned NULL!') AS [value3] ... 

Donc, ici vous pouvez voir clairement que Linq a converti le First () en TOP (1) et a également déterminé que "IT WAS NULL" ne pourrait jamais arriver (donc le 0 = 1) puisque le tout est basé sur une jointure externe et le toute la requête fusionne simplement en 'First Returned NULL!'.

Donc, c'était une erreur de perception de ma part de ne pas séparer dans mon esprit que Linq To SQL (et LINQ to Entities d'ailleurs) est très différent d'appeler les mêmes methods nommées sur les lists et autres.

J'espère que mon erreur est utile à quelqu'un d'autre.

Sans avoir votre database, je n'ai pas pu tester ce code, mais essayez quand même et voyez si cela fonctionne.

 var q = ( from st in Students join cr in Class_Rosters on st.StudentId equals cr.StudentId where cr.ClassId == 22898 join pp in Student_Program_Part on cr.StudentId equals pp.StudentId where pp.ProgramId == programId select new { StudentId = st.StudentId, refg = Student_Program_Participation_Values .Where(rudf => rudf.ProgramParticipationId == pp.ProgramParticipationId && rudf.UDFId == refugeeId) .ToArray() } ).ToArray(); var q2 = from x in q from refg in x.refg.DefaultIfEmpty() select new { StudentId = x.StudentId, Refugees = refg.Value ?? "IT WAS NULL", Refugee = refg .Select(rudf => (rudf.Value == null ? "IT WAS NULL" : "NOT NULL!")) .First() ?? "First Returned NULL!", }; q2.Dump(); 

Fondamentalement, l'idée est de capturer proprement les loggings de la database, de les mettre en memory, puis de faire toutes les choses null . Si cela fonctionne alors c'est à cause de l'échec de traduire le LINQ dans le même SQL. Le code SQL traduit peut parfois être un peu trop faible pour ne pas get les résultats escomptés. C'est comme si l'on traduisait l'anglais vers le français – vous pourriez ne pas get la traduction correcte.