Почему этот запрос LINQ to SQL прерывается, когда я выполняю ToList ()? - PullRequest
1 голос
/ 03 декабря 2010

Первоначально я объединял два набора результатов с кодом, подобным следующему:

var list1 = from a in IDataSourceObject
            blahblah
            select a;

var list2 = from a in IDataSourceObject2
            blahblah
            select a;    

var joinedlist = from a in list1
                 join b in list2 on a.id = b.id
                 into fishcakes
                 from b in fishcakes.DefaultIfEmpty()
                 orderby b.ranking
                 select new { blah=cakes, etc. }

Раньше это работало нормально, но затем я хотел немного отфильтровать список 1, поэтому я сделал это:

var list1 = from a in IDataSourceObject
            blahblah
            select a;

// ToList required because im calling a method in my code
var updatedList1 = from a in list1.ToList()
                   where myMethod(somestuff) == true
                   select a;   

var list2 = from a in IDataSourceObject2
            blahblah
            select a;    

var joinedlist = from a in updatedList1
                 join b in list2 on a.id = b.id
                 into fishcakes
                 from b in fishcakes.DefaultIfEmpty()
                 orderby b.ranking
                 select new { blah=cakes, etc. }

Однако я получаю сообщение об ошибке, в котором говорится, что OrderBy b.ranking имеет значение null.Это больше не объединяет результаты после создания ToList.Я проверил updatedList1 и сделал так, чтобы myMethod всегда возвращал true, поэтому, по сути, проблема заключается в использовании ToList ().

Я понимаю, что это может быть связано с отложенным выполнением, но я не имею ни малейшего представления о том,,Это должно быть точно так же.

У кого-нибудь есть предложения?

Ответы [ 4 ]

6 голосов
/ 03 декабря 2010

Вызов fishcakes.DefaultIfEmpty() может вернуть коллекцию с null.

Если вы вызываете .ToList(), все текущие результаты копируются в локальные (.Net) объекты, и все команды после .ToList() будут выполняться в вашей программе.

Если вы выполняете запрос к коллекциям .Net, то пытаетесь вызвать null.ranking - что выдает NullReferenceException. В то же время выполнение на SQL Server не вызывает исключений, потому что в SQL можно запросить свойство $ 1011 * (оно просто вернет null).

Для предотвращения исключений в вашем примере: вы можете либо отфильтровать элементы, у которых ranking равно null, либо заменить

orderby b.ranking 

примерно так (я полагаю, ranking - это int)

orderby b != null ? b.ranking : -1


Та же ситуация с материализацией ценностей. Например (предположим, что Item может иметь Category или может не иметь):

// this will work, because it's executed on SQL-side
db.Items
      .Select(x=>new { CatId = (int?)x.Category.Id, x.Id})
      .ToList();

// this will throw NullRefException, because it's executed against collection in .Net environment, not on SQL Server.
db.Items
      .ToList()
      .Select(x=>new { CatId = (int?)x.Category.Id, x.Id}); 

PS: Если вы используете Resharper, то в первом примере будет жаловаться, что приведение к int? не нужно. Не верь этому! )

2 голосов
/ 03 декабря 2010

join into аналогично левому внутреннему объединению в SQL.Таким образом, рыбные котлеты могут быть пустыми для некоторых a, и поэтому fishcakes.DefaultIfEmtpy() может возвращать ноль для некоторых a Попробуйте

var joinedlist = from a in updatedList1
                 join b in list2 on a.id = b.id
                 into fishcakes
                 from b in fishcakes
                 where b != null
                 orderby b.ranking
                 select new { blah=cakes, etc. }
0 голосов
/ 03 декабря 2010

Потому что вы пытаетесь объединить 2 разных (несовместимых) типа.Если вы возьмете list2 и выполните с ним аналогичную операцию .ToList(), это должно облегчить симптом.

0 голосов
/ 03 декабря 2010

Поскольку ToList () возвращает IEnumerable, который не является IQueryable

Пояснение:

Используя Linq to SQL, вы неявно используете IQueryable, поэтому эти операции выбора, объединения и упорядочения переводятся в SQL и выполняются на сервере БД. Однако преобразование updatedList1 в List не позволяет linq2sql преобразовать весь оператор в SQL-запрос, и его операторы выполняются один за другим, как в обычном Linq. Это может не только привести к некоторым ошибкам (например, NullReferenceException, упомянутым в ответе выше), но и гораздо менее эффективно, чем «чистое» выражение linq2sql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...