Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Matthieu MEZIL

I love .Net

Abonnements

Actualités

Locations of visitors to this page English blog
Locations of visitors to this blog
LINQ To Entities vs LINQ To SQL

Je reviendrai plus tard sur l'Entity Framework (EF) et l'Entity Data Model.

Dans ce post, je voulais juste illustrer les modifications sur le requêtage LINQ entre LINQ To Entities et LINQ To SQL. En effet, contre toute attente (du moins de mon point de vue), il existe des différences dans le requêtage LINQ.

Prenons la base Northwind on veut récupérer tous les produits regroupés par catégories. La manière la plus simple de faire cela est tout bêtement d'utiliser la relation qui existe entre Categories et Products.

Avec LINQ To SQL, cela se traduit par :

foreach (var c in context.Categories)
{
   Console.WriteLine(c.CategoryName);
   foreach (var p in c.Products)
      Console.WriteLine(" " + p.ProductName);
}

Avec LINQ To Entities, cette même requête pose deux problèmes :

Tout d'abord, et je ne me l'explique pas du tout, p n'est pas reconnu comme une instance de Products et du coup, le code ne compile pas.

Pourtant la propriété Products de Categories est de type System.Data.Objects.DataClasses.EntityCollection<Products> et EntityCollection<TEntity> : IEnumerable<TEntity>.

Mon réflexe a donc été de ne pas utiliser le deuxième var :

foreach (var c in context.Categories)
{
   Console.WriteLine(c.CategoryName);
   foreach (Products p in c.Products)
      Console.WriteLine(" " + p.ProductName);
}

Ce code compile mais là, surprise à l'exécution, il n'y a aucun produit !

En effet, avec LINQ To Entities, les entités liées par une relation ne sont pas récupérées (par défaut). Il faut donc le préciser avec la méthode Include :

foreach (var c in context.Categories.Include("Products"))
{
   Console.WriteLine(c.CategoryName);
   foreach (Products p in c.Products)
      Console.WriteLine(" " + p.ProductName);
}

Soit dit en passant, je trouve que ce n'est pas super de passer Products en chaine de caractères. Du coup, le compilateur ne peut pas vérifier les erreurs. Sauf si vous utilisez ceci. Attention ExpressionType.Cast n'existe plus. Pour ma part, je l'ai réécris comme ça :

public static PropertyInfo GetProperty(Expression<Func<T, object>> selector)
{
   if (selector == null)
      throw new ArgumentNullException();
   Expression e = selector.Body;
   while (!((e is MemberExpression) && (e.NodeType == ExpressionType.MemberAccess) && ((e as MemberExpression).Member is PropertyInfo)))
   {
      if (e is UnaryExpression)
      {
         switch (e.NodeType)
         {
            case ExpressionType.Convert:
            case ExpressionType.ConvertChecked:
            case ExpressionType.TypeAs:
               e = (e as UnaryExpression).Operand;
               break;
            default:
               throw new ArgumentException();
         }
      }
      else
         throw new ArgumentException();
   }
   return (e as MemberExpression).Member as PropertyInfo;
}

Du coup le Include peut alors s'écrire comme ceci :

context.Categories.Include(ReflectionHelper<Categories>.GetProperty(c => c.Products).Name)

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié mardi 11 décembre 2007 21:37 par Matthieu MEZIL

Classé sous : , , , ,

Commentaires

# re: LINQ To Entities vs LINQ To SQL @ mardi 11 décembre 2007 22:49

On dirait un équivalent de LoadWith/Associate pour LINQ To SQL. Il faudrait voir le code SQL généré par les requêtes LINQ mais c'est à cela que ca me penser....

Thomas LEBRUN

# re: LINQ To Entities vs LINQ To SQL @ vendredi 21 décembre 2007 12:39

Oui et non Thomas.

En effet, le LoadWith/Associate permet de récupérer les infos en une seule requête. Cependant, si tu ne l'utilises pas et que tu veuilles récupérer les données de ton EntitySet, les requêtes sont générées à la volée et tu récupères bien les objets liés.

Avec EF, tu as une EntityCollection<T> (à la place de l'EntitySet<T>) et celles-ci est vide si tu n'as pas fait le Include (même si tu as des données en base). Il n'y a pas de requêtage à la volée lors du parcours de l'EntityCollection ce qui est un peu destabilisant quand on a l'habitude de LINQ To SQL. En revanche, si tu veux réaliser le chargement de tes relations plus tard, tu peux utiliser la méthode Load.

Cela s'explique par le faire que l'EF gère le cache contrairement à LINQ To SQL. Je m'explique : avec LINQ To SQL (sans le LoadWith/Associate), à chaque fois que tu vas appeler une propriété de navigation, une nouvelle requête va être envoyée à la base, même si tu as récupéré cette même entité 1 seconde plus tôt. Cela permet d'assurer la validité des données mais au détriment des performances (d'où l'intérêt du LoadWith/Associate, particulièrement dans le cas d'une application web). Avec l'EF, il va regarder dans son cache et c'est tout. Du coup, par défaut il n'y a rien. Quand tu fais un Load tu remplis le cache. De même, quand tu exécute une requête LINQ To Entities, tu remplis le cache.

Donc pour répondre à ta question, oui c'est un peu la même chose mais il faut savoir cela avant Wink

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Power Tools 2008 CTP Juillet par Noham Choulant le il y a 18 minutes

- Disparition de variables de session PHP après une redirection ? par MadMatt le il y a 10 heures et 15 minutes

- [MOSS 2007] Publier ses formulaires InfoPath via feature par Adrien Siffermann le il y a 13 heures et 22 minutes

- Imagine Cup 2008 - Paris - Les résultats par TheSaib .NET blog le il y a 14 heures et 44 minutes

- L'Egypte accueille Imagine Cup 2009 par Code is poetry le il y a 14 heures et 56 minutes

- PowerShell : Mise en ligne de fonctions intéressantes pour SharePoint par Blog Technique de Romelard Fabrice le il y a 16 heures et 4 minutes

- Raccourcis clavier et CRM 4 par Clark, C#, MSCRM, SBS le il y a 20 heures et 9 minutes

- [Silverlight] Comment échanger des données entre une application Silverlight et une page ASP.NET via cookies ? par Thomas Lebrun le il y a 20 heures et 45 minutes

- SharePoint 2007 : Trouver les fichiers CheckOut dans une librairie de document par Philippe Sentenac [MVP SharePoint] le il y a 23 heures et 13 minutes

- [Open XML] Travailler avec Open XML : Linq To XML (Partie 2 - Requêtes/XPath) par Julien Chable le 07-08-2008, 02:05