Entity framework - avoir un include typé

0/5 (1 avis)

Snippet vu 7 877 fois - Téléchargée 20 fois

Contenu du snippet

Entity Framework propose une méhtode Include permettant d'inclure des objets connexes lors du chargement de certaines entités. Cette méthode prend un String en paramètre, ce qui ne permet pas d'avoir une vérification lors de la compilation.

Le bout de code ci-dessous permet de générer différentes méthodes Include permettant d'avoir des includes typés. Il existe de nombreuses solutions permettant d'attendre cette objectif, cette solution permet d'inclure plusieurs profondeurs d'objets connexes, y compris lorsqu'un de ces objets est une collection.

Il est ainsi possible de faire :

var q = entities.Orders.Include(o => o.Customer.Addresses, a => a.Country).Where(o => o.CustomerId == 3);

La source est composé de 2 fichiers, un fichier ExpressionExtensions contenant quelques méthodes d'extension permettant de connaitre le nom d'une propriété à partir d'une lambda et d'un fichier T4 générant les différentes méthodes Include.

Source / Exemple :


// ExpressionExtensions.cs

    public static class ExpressionExtensions
    {
        public static String GetPropertyName<T, TProperty>(this Expression<Func<T, TProperty>> expression)
        {
            return GetPropertyName(expression);
        }
        public static String GetPropertyName(this Expression expression)
        {
            LambdaExpression lambdaExpression = expression as LambdaExpression;
            if (lambdaExpression != null)
            {
                expression = lambdaExpression.Body;
            }

            MemberExpression memberExpression = expression as MemberExpression;
            if (memberExpression != null)
            {
                String parentPropertyName = String.Empty;
                if (memberExpression.Expression is MemberExpression)
                {
                    parentPropertyName = ExpressionExtensions.GetPropertyName(memberExpression.Expression) + ".";
                }
                return parentPropertyName + memberExpression.Member.Name;
            }

            throw new NotImplementedException();
        }
    }

// ObjectQueryExtensions.Include.tt

<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Windows.Forms.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #> 
<#
	Byte maxDepth = 6;
#>

using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Linq.Expressions;

namespace Magelia.WebStore.Data.Entities
{
	public static partial class ObjectQueryExtensions
  	{
	    internal static String GetPath(params LambdaExpression[] lambdas)
        {
            return String.Join(".",
                lambdas
                .Select(l => l.GetPropertyName())
                .ToArray()
            );
        }

<#
	for(Byte i = 1; i < maxDepth; i++)
	{
        int combinationCount = (int)Math.Pow(2, i);
        for (int j = 0; j < combinationCount; j++)
        {
            WriteMethod(i, j); 
        }
	}
#>
  	}
}
 
<#+
  	void WriteMethod(Byte depth, int combinationValue)
	{
        String[] genericsType = new String[depth+1];
		genericsType[0] = "TEntity"; 
		int i = depth-1;
        while (i >= 0)
        {
			String genericType = "T" + i.ToString();
            if ((combinationValue & (1 << i)) != 0)
            {
                genericType = "IEnumerable<" + genericType + ">";
            }
			genericsType[i+1] = genericType; 
            i--;
        }
		String[] parametersType = new String[depth]; 
		for(i = 0; i < depth; i++)
		{
			parametersType[i] = String.Format("Expression<Func<T{0}, {1}>> selector{2}", (i == 0) ? "Entity" : (i-1).ToString(), genericsType[i+1], i); 
		}
#>
		public static ObjectQuery<TEntity> Include<TEntity, <#= String.Join(", ", Enumerable.Range(0, depth).Select(j => "T" + j.ToString()).ToArray()) #>>(this ObjectQuery<TEntity> objectSet, <#= String.Join(", ", parametersType) #>)
			where TEntity : class
		{
			return objectSet.Include(GetPath(<#= String.Join(", ", Enumerable.Range(0, depth).Select(j => "selector" + j.ToString()).ToArray()) #>));
		}
<#+
	}
#>

Conclusion :


Plus d'information sur mon blog : http://blogs.developpeur.org/cyril/archive/2012/01/17/include-typ-et-entity-framework.aspx

A voir également

Ajouter un commentaire Commentaire
cs_bigboss9 Messages postés 162 Date d'inscription jeudi 22 janvier 2004 Statut Membre Dernière intervention 20 juillet 2013
25 sept. 2012 à 14:51
Oups, tu pousses la porte, avance au fond du couloir, entre chez CodeProject / StackOverflow et poste ton code là bas.
Ici, on est chez les newbies des prairies et on tient à y rester ! Alors les gens qui se la pètent avec leur code trop compliqués, on en veut pas hein ;)

Allez, dégage l'expert et laisse nous à nos éditeurs de textes, compteurs de lettres, et autres softwares de-la-mort-qui-tue.

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.