Как мне обработать серию левых объединений в Linq to Objects? - PullRequest
0 голосов
/ 27 февраля 2012

Реальный запрос в linq к объектам против БД, подобный этому, работает просто отлично. При попытке выполнить модульное тестирование запроса с использованием linq to Objects я получаю исключение нулевой ссылки.

Я воспроизвел это в linqPad.

 void Main()
{
    var _news= new [] {new {ID=0, ExpiryDate=(DateTime?)null }, new {ID=1,ExpiryDate=(DateTime?)DateTime.UtcNow.AddDays(-1)}};
    var _newsRegionSource = new RegionSource[]{};
    var _entitledRegions=new Region[] {};

    var validNews = from n in _news.Where(n=>n.ExpiryDate==null || n.ExpiryDate>DateTime.UtcNow)
        select n;
    var q = from n in validNews

            join r in _newsRegionSource
            on n.ID equals r.ID into rLeft
            from rn in rLeft.DefaultIfEmpty()

            join erL in _entitledRegions 
            // adding .DefaultIfEmpty() here instead moves the exception to erL.ID
            //NullReferenceException underlining rn at rn.RegionID
            on rn.RegionID equals erL.ID into erLeft
            from er in erLeft.DefaultIfEmpty()

            where rn==null | (rn.ID==n.ID && er!=null)
            select new {News=n,RegionID=(rn==null? (byte?)null: rn.RegionID)};
            var materialized=q.ToArray();
        materialized.Dump();

}

public class Region
{
    public byte ID {get;set;}
}
public class RegionSource
{
    public int ID{get;set;}
    public byte RegionID{get;set;}
}

Тоже попробовал

  • убедившись, что во всех исходных массивах был хотя бы 1 элемент (но они все равно приводят к 0 строкам для этого конкретного запроса / случая),
  • упаковка массивов в .AsQueryable()

Как мне обработать левые объединения, возможно, 0 строк в Linq to Objects?

1 Ответ

0 голосов
/ 13 марта 2012

Поведение сущностей немного отличается от поведения LINQ для объектов, связанных с левыми внешними объединениями, как вы узнали здесь.Вы все еще можете заставить его работать с очень легкой настройкой.Хитрость заключается в предоставлении выражения соединения, которое позволяет избежать разыменования null.

Моя первая попытка была у меня с выражением соединения:

        on (rn == null : Int32.MinValue : rn.RegionID) equals erL.ID into erLeft

Меньше, чем удовлетворяющее, так как Int32.MinValue похоже на этоявляется как произвольным значением, так и потому, что оно может быть допустимым значением RegionID в зависимости от вашего использования.Другой вариант - использовать обнуляемое целое число, которое я считаю более удовлетворительным, поскольку оно дает тот же результат без угона случая Int32.MinValue.

        on (rn == null ? (Int32?) null : rn.RegionID) equals erL.ID into erLeft

Теперь изменив ИЛИ (|) в следующем условном выражениидля короткого замыкания (||) следующим образом:

        where rn==null || (rn.ID==n.ID && er!=null)

Вместо NullReferenceException вы должны получить один результат News, RegionID сейчас, как и ожидалось.

...