2010-10-14 7 views
0

Note: Je sais qu'il y a un certain nombre de questions autour de problèmes avec Linq. Inclure (tableau) ne pas charger des données, je crois que j'ai épuisé les options les gens ont énuméré, et encore eu des problèmes.Linq2Entities Inclure avec Skip/Take-load problème

J'ai une grande requête Linq2Entities sur une application que je gère. La requête est construite en tant que tel:

IQueryable<Results> query = context.MyTable 
    .Where(r => 
    r.RelatedTable.ID == 2 && 
    r.AnotherRelatedTable.ID == someId); 

Ensuite prédicats sont construits en fonction de diverses logique métier, tels que:

if (sortColumn.Contains("dob ")) 
{ 
    if (orderByAscending) 
     query = query.OrderBy(p => p.RelatedTable.OrderByDescending(q => q.ID).FirstOrDefault().FieldName); 
    else 
     query = query.OrderByDescending(p => p.RelatedTable.OrderByDescending(q => q.ID).FirstOrDefault().FieldName); 
} 

Remarque - il y a toujours un ordre de tri fourni.

A l'origine les tableaux inclus ont été mis au début, après avoir lu des articles tels que le fameux Tip 22, alors maintenant ils se font à la fin (ce qui n'a pas résolu le problème):

var resultsList = (query.Select(r => r) as ObjectQuery<Results>) 
    .Include("RelatedTable") 
    .Include("AnotherRelatedTable") 
    .Skip((page - 1) * rowsPerPage) 
    .Take(rowsPerPage); 

apparemment au random (environ pour chaque 5000 utilisateurs du site, ce problème arrive une fois) les données RelatedTable ne se chargeront pas. Il peut être brutalement forcé en appelant load sur la table associée. Mais même l'échec de chargement n'est pas cohérent, j'ai exécuté la requête dans testing et cela a fonctionné, mais la plupart du temps non, sans changer le code ou les données. C'est bon, quand le skip et la prise ne sont pas inclus, et tout l'ensemble de données est retourné, mais je m'attendrais à ce que l'omission et la prise soient faites sur l'ensemble de données complet - il semble bien être de profiler le SQL

MISE À JOUR 16/11/10: J'ai profilé le SQL par rapport à un jeu de données de problème, et j'ai été capable de reproduire la requête échouant environ 9/10 fois, mais réussissant le reste. Le SQL en cours d'exécution est identique lorsque la requête échoue ou réussit sauf, comme prévu, pour les paramètres passés au SQL.

Le problème a été résolu avec le changement suivant, mais la question demeure: pourquoi cela devrait-il l'être?

A défaut - se LINQ pour gérer les lignes:

var resultsList = (query.Select(r => r) as ObjectQuery<Results>) 
    .Include("RelatedTable") 
    .Include("AnotherRelatedTable") 
    .Skip((page - 1) * rowsPerPage) 
    .Take(rowsPerPage) 
    .ToList(); 

travail - énumérer les données puis obtenir les lignes:

var resultsList = (query.Select(r => r) as ObjectQuery<Results>) 
    .Include("RelatedTable") 
    .Include("AnotherRelatedTable") 
    .ToList() 
    .Skip((page - 1) * rowsPerPage) 
    .Take(rowsPerPage); 

Malheureusement, le SQL de cette requête crée contient des données de schéma sensibles, donc je on ne peut pas le poster, il fait aussi 1400 lignes, donc je ne le soumettrais pas au public de toute façon!

+0

Est-ce L2E ou L2SQL? –

+0

Désolé, L2E ... je ne sais pas pourquoi j'écrivais L2SQL! – Timbo

+0

Donc, vous dites que le SQL est le même pour une demande de requête de travail par rapport à une demande de requête qui échoue? –

Répondre

2

Le seul effet de Take() consiste à modifier le code SQL généré. À part cela, Entity Framework ne s'en soucie pas du tout. Idem pour .Skip(). Il est difficile de croire que cela aurait un effet sur la matérialisation de la requête (bien que des choses plus étranges se soient produites).

Alors que pourrait causer ce comportement? En haut de ma tête:

  1. Un bogue dans votre application ou mappage qui provoque une requête incorrecte à générer.
  2. Un bogue dans Entity Framework qui provoquerait la matérialisation incorrecte des données renvoyées dans les objets dans certaines circonstances.
  3. Données incorrectes dans votre base de données.
  4. Un bogue dans l'analyseur SQL de votre base de données.

Je ne pense pas que vous allez aller beaucoup plus loin avec ceci jusqu'à ce que vous puissiez capturer le SQL généré et l'exécuter vous-même. Ce n'est pas vraiment difficile, car vous pouvez configurer un profileur SQL avec un filtre approprié. Si vous trouvez que le SQL généré est différent dans le cas de buggy, vous pouvez travailler en arrière à partir de là. Si vous trouvez que le SQL généré est identique dans le cas bogué, l'étape suivante consisterait à regarder les lignes retournées, de préférence dans le même contexte que l'application exécutée. En bref, je pense qu'il suffit de continuer à peaufiner votre profilage SQL jusqu'à ce que vous ayez les informations dont vous avez besoin.

+1

Je déplacerais le numéro 3 au-dessus du numéro 2. En cas de doute, supposez que votre code/données est faux, pas vos outils. – tster

+0

@tster: Entièrement d'accord. –

+0

Merci Craig. Je ne pourrais pas être plus d'accord que la réponse la plus probable est mes données. Fait intéressant à présent, j'ai travaillé autour de lui en énumérant la requête dans une liste, puis faire le saut et prendre la liste. Cela fonctionne très bien ... je ne sais pas exactement ce que cela signifie pour le problème! Je vais essayer d'avoir une autre chance de profiler la bonne/mauvaise requête au cours des prochains jours, je suis d'accord en principe que c'est la meilleure option, mais scarily le sql généré est de 2000 lignes. Quelqu'un a choisi le mauvais outil pour le travail que je pense! : P – Timbo

Questions connexes