2011-12-06 4 views
2

Прошу простить любую наивность, я новичок в мире C#. Дайте мне знать, если я оставил полезную информацию.Предложение WHERE в запросе LINQ кажется неудачным

Я строй пользовательских SiteMapProvider для портала клиента для Dynamics CRM 2011. Сначала я инициализировать массив:

public Adx_webpage[] WebPages; 

который получает населенный таким образом:

public MyProvider() 
{ 
    WebPages = (FROM p in CrmContext.Adx_webpageSet WHERE p.Adx_HiddenFromSitemap != true SELECT p).ToArray(); 
} 

Позже, я стараюсь запросить веб-страницы [] следующим образом:

Adx_webpage[] childPages = (FROM p in WebPages WHERE p.adx_parentpageid.Id == page.Id SELECT p).ToArray(); 

Когда я запускаю это через отладчик, я получаю Nul lReferenceException, которое указывает на условие в моем предложении WHERE, говорящее, что p.adx_parentpageid.Id имеет значение null, что верно для домашней страницы сайта. Что приводит к вопросу:

Зачем этот запрос появляется на домашней странице как p в моем запросе? Что я недопонимаю?

+0

Вы лениво загружаете свои сущности? Возможно, вам нужно загрузить дочерние объекты, если они все равны нулю. – user1231231412

+1

Является ли страница скрытой от карты сайта? –

+1

Что такое тип данных p.adx_parentpageid.Id? Я думаю, что его фактический p.adx_parentpageid, который является null, и он бросает с вами попытку доступа к свойству Id. Если p.adx_parentpageid может быть пустым, тогда вам нужно закодировать это условие. – user957902

ответ

4

Вашей первой линией

WebPages = (FROM p in CrmContext.Adx_webpageSet WHERE p.Adx_HiddenFromSitemap != true SELECT p).ToArray(); 

вернет вам все страницы, которые не скрыты в карте сайта. Но это также включает вашу домашнюю страницу, у которой нет родительского идентификатора. Поэтому, когда ваш второй запрос перечислит эту коллекцию, он попытается получить доступ к этому свойству, которое является нулевым, и выбрасывает исключение нулевой ссылки. Вам просто нужно удовлетворить это в своем запросе.

Adx_webpage[] childPages = 
(FROM p in WebPages WHERE 
p.adx_parentpageid.Id != null && 
p.adx_parentpageid.Id == page.Id SELECT p).ToArray(); 
1

Проблема заключается в .ToArray() для первого запроса. Этот запрос LINQ создает нативный запрос к провайдеру CrmContext:

WebPages = (FROM p in CrmContext.Adx_webpageSet WHERE p.Adx_HiddenFromSitemap != true SELECT p).ToArray(); 

.ToArray() вызывает запрос Linq для запуска немедленно и возвращает обычный старый массив объектов. Массив не привязан к вашему объекту CrmContext.

Однако этот запрос использует Linq to Objects, чтобы перебрать массив, возвращенный при первом вызове. Он не генерирует собственный запрос поставщику CrmContext.

Adx_webpage[] childPages = (FROM p in WebPages WHERE p.adx_parentpageid.Id == page.Id SELECT p).ToArray());  

Сво фактически то же самое, как с помощью цикла Еогеаспа перебрать каждый элемент в массиве, так что вы должны беспокоиться о проверке возможных нулевых значений, которые были возвращены на ваш первый запрос.

+0

ОК, это имеет смысл. Я хотел бы ударить по базе данных только один раз, поэтому я делаю первый запрос, чтобы получить ВСЕ страницы в БД, а затем запросить результирующий массив после этого; LINQ, похоже, имеет для этого большой смысл. Есть ли лучший способ сделать это? – saturdayplace

+0

Linq to Objects подходит для этого. Вам просто нужно помнить, что он просто запускает .net-код под ним, и вы не защищены от нулевых ссылок, как если бы вы использовали для собственного запроса. Если объект не имеет отношения, он не будет просто исключен, и он собирается выбросить исключение нулевой ссылки. – user957902

1

Я не понимаю ваш вопрос. Вы говорите, что домашняя страница является веб-страницей, и она НЕ скрыта из файла Sitemap, поэтому почему не будет, вы ожидаете, что домашняя страница будет отображаться в вашем запросе как p?

Во всяком случае, вы можете просто пропустить что-нибудь с p == null:

Adx_webpage[] childPages = (FROM p in WebPages 
          WHERE p.adx_parentpageid != null && 
            p.adx_parentpageid.Id == page.Id 
          SELECT p).ToArray();