Оставить соединение с помощью LINQ - PullRequest
8 голосов
/ 11 мая 2009

Может ли кто-нибудь дать мне пример того, как выполнить операцию левого соединения, используя выражения LINQ / lambda?

Ответы [ 5 ]

6 голосов
/ 11 мая 2009

Страница LINQ to SQL в MSDN дает пример того, как этого добиться. Код должен быть в значительной степени идентичен для LINQ to Objects.

Ключом здесь является звонок на DefaultIfEmpty.

Dim q = From e In db.Employees _
        Group Join o In db.Orders On e Equals o.Employee Into ords = Group _
        From o In ords.DefaultIfEmpty _
        Select New With {e.FirstName, e.LastName, .Order = o}

Если вам нужна помощь в преобразовании этого в C #, просто спросите.

4 голосов
/ 11 мая 2009

Вот пример левого соединения в LINQ.

0 голосов
/ 21 мая 2015

хорошо, я попытался воспроизвести знаменитое левое соединение, где клавиша b равна нулю, и в результате я получил такой метод расширения (с небольшим воображением вы можете изменить его, чтобы просто сделать левое соединение):

    public static class extends
{
    public static IEnumerable<T> LefJoinBNull<T, TKey>(this IEnumerable<T> source, IEnumerable<T> Target, Func<T, TKey> key)
    {
        if (source == null)
            throw new ArgumentException("source is null");

        return from s in source
               join j in Target on key.Invoke(s) equals key.Invoke(j) into gg
               from i in gg.DefaultIfEmpty()
               where i == null
               select s;
    }
}
0 голосов
/ 18 октября 2012

Я нашел то, что мне нравится, это объединить OuterCollection.SelectMany() с InnerCollection.DefaultIfEmpty(). Вы можете запустить следующее в LINQPad , используя режим «C # Statements».

var teams = new[] 
    { 
        new { Id = 1, Name = "Tigers" }, 
        new { Id = 2, Name = "Sharks" }, 
        new { Id = 3, Name = "Rangers" },
    };

var players = new[] 
    { 
        new { Name = "Abe", TeamId = 2}, 
        new { Name = "Beth", TeamId = 4}, 
        new { Name = "Chaz", TeamId = 1}, 
        new { Name = "Dee", TeamId = 2}, 
    };

// SelectMany generally aggregates a collection based upon a selector: from the outer item to
//  a collection of the inner item.  Adding .DefaultIfEmpty ensures that every outer item
//  will map to something, even null.  This circumstance makes the query a left outer join.
// Here we use a form of SelectMany with a second selector parameter that performs an
//  an additional transformation from the (outer,inner) pair to an arbitrary value (an
//  an anonymous type in this case.)
var teamAndPlayer = teams.SelectMany(
    team => 
        players
        .Where(player => player.TeamId == team.Id)
        .DefaultIfEmpty(),
    (team, player) => new 
        { 
             Team = team.Name, 
             Player = player != null ? player.Name : null 
        });

teamAndPlayer.Dump();

// teamAndPlayer is:
//     { 
//         {"Tigers", "Chaz"},
//         {"Sharks", "Abe"},
//         {"Sharks", "Dee"},
//         {"Rangers", null}
//     }

Экспериментируя с этим, я обнаружил, что иногда вы можете опустить нулевую проверку player в экземплярах анонимного типа. Я думаю, что это имеет место при использовании LINQ-to-SQL в базе данных (вместо этих массивов здесь, которые, я думаю, делает это LINQ-to-objects или что-то в этом роде). Я думаю, что пропуск пустой проверки работает в LINQ -to-SQL, потому что запрос переводится в SQL LEFT OUTER JOIN, который сразу переходит к соединению null с внешним элементом. (Обратите внимание, что значение свойства анонимного объекта должно быть равно нулю; поэтому, если вы хотите безопасно включить int, скажем, вам понадобится что-то вроде: new { TeamId = (int?)player.TeamId }.

0 голосов
/ 28 января 2010

Например:

IQueryable<aspnet_UsersInRole> q = db.aspnet_Roles
                    .Select(p => p.aspnet_UsersInRoles
                        .SingleOrDefault(x => x.UserId == iduser));

Предоставит вам список ролей из членства asp.net с нулями, в которых он не соответствует указанному пользователю (ключ iduser)

...