Expression Lambda vers l'arborescence Expression <T> (tranche 2 - jointure)
Comment mettre un éléphant dans un réfrigérateur? Vous le découpez ... Sooo, comment traduisez-vous une requête lambda en arbre d'expression? Vous le tranchez ...
Il s'agit d'une série de 3 tranches d'expression lambda vers l'arbre d'expression.
Slice 1. Ici , Comment faire .join () en utilisant l'exemple Microsoft.
Tranche 2 (cette tranche). Chargement hâtif avec des paramètres différents de ceux utilisés dans la tranche 1.
Tranche 3. Ici , comment terminer la requête avec .where () et .Select ().
Dans cette tranche, j'essaie de convertir la requête suivante en syntaxe d'arbre d'expression:
IQueryable<A> As = db.A
.Join(
db.B,
_a => _a.bID,
_b => _b.ID,
(a, b) => new { a, b })
//The next two statements are going to next slice.
.Where(s=> s.b.Name == "xpto")
.Select(s => s.a);
Dans la tranche 1, j'avais:
Exemple précédent de transformation:
var query = people.AsQueryable().Join(pets,
person => person,
pet => pet.Owner,
(person, pet) =>
new { OwnerName = person.Name, Pet = pet.Name });
Cela a abouti à une réponse @NetMage, qui a fait l'affaire avec:
// Build Queryable.Join<TOuter,TInner,TKey,TResult> and use as query expression
// IQueryable<TOuter>
var arg0 = Expression.Constant(people.AsQueryable());
// IEnumerable<TInner>
var arg1 = Expression.Constant(pets);
// TOuter person
var arg2p = Expression.Parameter(people.GetType().GetGenericArguments()[0], "person");
// also TKey person
// Expression<Func<TOuter,TKey>>: person => person
var arg2 = Expression.Quote(Expression.Lambda(arg2p, arg2p));
// TInner pet
var arg3p = Expression.Parameter(pets.GetType().GetGenericArguments()[0], "pet");
// TKey pet.Owner
var arg3body = Expression.Property(arg3p, "Owner");
// Expression<Func<TInner,TKey>>: pet => pet.Owner
var arg3 = Expression.Quote(Expression.Lambda(arg3body, arg3p));
// TResult = typeof(new { string OwnerName , string Pet })
var anonymousType = (new { OwnerName = default(string), Pet = default(string) }).GetType();
// .ctor
var arg4Constructor = anonymousType.GetConstructors()[0];
// person.Name
var arg4PersonName = Expression.Property(arg2p, "Name");
// pet.Name
var arg4PetName = Expression.Property(arg3p, "Name");
var arg4Args = new[] { arg4PersonName, arg4PetName };
// new[] { .OwnerName, .Pet }
var arg4Members = anonymousType.GetProperties();
// new { OwnerName = person.Name, Pet = pet.Name }
var arg4body = Expression.New(arg4Constructor, arg4Args, arg4Members);
// Expression<Func<TOuter,TInner,TResult>>: (person,pet) => new { OwnerName = person.Name, Pet = pet.Name }
var arg4 = Expression.Quote(Expression.Lambda(arg4body, arg2p, arg3p));
var joinGenericMI = typeof(Queryable).GetMethod("Join", 5);
var joinMI = joinGenericMI.MakeGenericMethod(new[] { arg2p.Type, arg3p.Type, arg2.ReturnType, anonymousType });
var qExpr = Expression.Call(joinMI, arg0, arg1, arg2, arg3, arg4);
Pour cette tranche, la déclaration suivante - présentée dans la tranche précédente - devait être modifiée:
// TResult = typeof(new { string OwnerName , string Pet })
var anonymousType = (new { OwnerName = default(string), Pet = default(string) }).GetType();
@NetMage l'a adapté aux génériques A et B:
// TResult = typeof(new { A , B })
var anonymousType = (new { A = db.A.FirstOrDefault(), db.B = B.FirstOrDefault() }).GetType();
et
var arg4Constructor = anonymousType.GetConstructors()[0];
// person.Name
var arg4PersonName = Expression.Property(arg2p, "Name");
// pet.Name
var arg4PetName = Expression.Property(arg3p, "Name");
est devenu (adapté aux génériques A et B):
// object A
var arg4A = arg2p;
// object B
var arg4B = arg3p;
Il est maintenant nécessaire de filtrer le résultat par b.Name et de sélectionner une (tranche suivante).
Réponses
Pour obtenir le type de retour de la Joinméthode, procédez comme suit:
// TResult = typeof(new { A , B })
var anonymousType = (new { A = db.A.FirstOrDefault(), db.B = B.FirstOrDefault() }).GetType();
Vous devez créer un type anonyme où le membre Aa un type d' db.Aentité de type. Si vous utilisez par exemple typeof(A), alors vous aurez Aavec type Type, complètement sans rapport avec le Join. (Si vous connaissiez le type d'entité de A, vous pouvez simplement utiliser defaultcomme je l'ai fait: par exemple, si db.Aest DbSet<AClass>alors utilisez A = default(AClass).)
Puisque vous ne référencez aucune propriété dans le Joinrésultat, vous utilisez simplement les paramètres:
// object A
var arg4A = arg2p;
// object B
var arg4B = arg3p;