Saltar al contenido

Entity framework left join

Hola usuario de nuestro sitio web, tenemos la solución a lo que buscas, has scroll y la hallarás aquí.

Solución:

adaptado de MSDN, cómo unirse a la izquierda usando EF 4

var query = from u in usergroups
            join p in UsergroupPrices on u.UsergroupID equals p.UsergroupID into gj
            from x in gj.DefaultIfEmpty()
            select new  
                UsergroupID = u.UsergroupID,
                UsergroupName = u.UsergroupName,
                Price = (x == null ? String.Empty : x.Price) 
            ;

Puede ser un poco exagerado, pero escribí un método de extensión, así que puedes hacer un LeftJoin utilizando el Join sintaxis (al menos en la notación de llamada al método):

persons.LeftJoin(
    phoneNumbers,
    person => person.Id,
    phoneNumber => phoneNumber.PersonId,
    (person, phoneNumber) => new
        
            Person = person,
            PhoneNumber = phoneNumber?.Number
        
);

Mi código no hace más que agregar un GroupJoin y un SelectMany llamar al árbol de expresión actual. Sin embargo, parece bastante complicado porque tengo que construir las expresiones yo mismo y modificar el árbol de expresiones especificado por el usuario en el resultSelector parámetro para mantener todo el árbol traducible por LINQ-to-Entities.

public static class LeftJoinExtension

    public static IQueryable LeftJoin(
        this IQueryable outer,
        IQueryable inner,
        Expression> outerKeySelector,
        Expression> innerKeySelector,
        Expression> resultSelector)
    
        MethodInfo groupJoin = typeof (Queryable).GetMethods()
                                                 .Single(m => m.ToString() == "System.Linq.IQueryable`1[TResult] GroupJoin[TOuter,TInner,TKey,TResult](System.Linq.IQueryable`1[TOuter], System.Collections.Generic.IEnumerable`1[TInner], System.Linq.Expressions.Expression`1[System.Func`2[TOuter,TKey]], System.Linq.Expressions.Expression`1[System.Func`2[TInner,TKey]], System.Linq.Expressions.Expression`1[System.Func`3[TOuter,System.Collections.Generic.IEnumerable`1[TInner],TResult]])")
                                                 .MakeGenericMethod(typeof (TOuter), typeof (TInner), typeof (TKey), typeof (LeftJoinIntermediate));
        MethodInfo selectMany = typeof (Queryable).GetMethods()
                                                  .Single(m => m.ToString() == "System.Linq.IQueryable`1[TResult] SelectMany[TSource,TCollection,TResult](System.Linq.IQueryable`1[TSource], System.Linq.Expressions.Expression`1[System.Func`2[TSource,System.Collections.Generic.IEnumerable`1[TCollection]]], System.Linq.Expressions.Expression`1[System.Func`3[TSource,TCollection,TResult]])")
                                                  .MakeGenericMethod(typeof (LeftJoinIntermediate), typeof (TInner), typeof (TResult));

        var groupJoinResultSelector = (Expression, LeftJoinIntermediate>>)
                                      ((oneOuter, manyInners) => new LeftJoinIntermediate OneOuter = oneOuter, ManyInners = manyInners);

        MethodCallExpression exprGroupJoin = Expression.Call(groupJoin, outer.Expression, inner.Expression, outerKeySelector, innerKeySelector, groupJoinResultSelector);

        var selectManyCollectionSelector = (Expression, IEnumerable>>)
                                           (t => t.ManyInners.DefaultIfEmpty());

        ParameterExpression paramUser = resultSelector.Parameters.First();

        ParameterExpression paramNew = Expression.Parameter(typeof (LeftJoinIntermediate), "t");
        MemberExpression propExpr = Expression.Property(paramNew, "OneOuter");

        LambdaExpression selectManyResultSelector = Expression.Lambda(new Replacer(paramUser, propExpr).Visit(resultSelector.Body), paramNew, resultSelector.Parameters.Skip(1).First());

        MethodCallExpression exprSelectMany = Expression.Call(selectMany, exprGroupJoin, selectManyCollectionSelector, selectManyResultSelector);

        return outer.Provider.CreateQuery(exprSelectMany);
    

    private class LeftJoinIntermediate
    
        public TOuter OneOuter  get; set; 
        public IEnumerable ManyInners  get; set; 
    

    private class Replacer : ExpressionVisitor
    
        private readonly ParameterExpression _oldParam;
        private readonly Expression _replacement;

        public Replacer(ParameterExpression oldParam, Expression replacement)
        
            _oldParam = oldParam;
            _replacement = replacement;
        

        public override Expression Visit(Expression exp)
        
            if (exp == _oldParam)
            
                return _replacement;
            

            return base.Visit(exp);
        
    

Haga su vida más fácil (no use unirse al grupo):

var query = from ug in UserGroups
            from ugp in UserGroupPrices.Where(x => x.UserGroupId == ug.Id).DefaultIfEmpty()
            select new 
             
                UserGroupID = ug.UserGroupID,
                UserGroupName = ug.UserGroupName,
                Price = ugp != null ? ugp.Price : 0 //this is to handle nulls as even when Price is non-nullable prop it may come as null from SQL (result of Left Outer Join)
            ;

Te mostramos las reseñas y valoraciones de los lectores

Recuerda que tienes concesión de agregar una reseña si diste con la contestación.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *