Использование linq с Sharepoint и удаление объектов - PullRequest
3 голосов
/ 18 марта 2009

Как разместить ссылку на дочерний веб-узел в следующем запросе?

using (SPSite spSite = Utility.GetElevatedSite(_rootUrl))
{
    from SPWeb web in spSite.AllWebs
    where web.ServerRelativeUrl.ToLower() == path
    from SPWeb subWeb in web.Webs                            
    select subWeb
}

Нужно ли мне даже беспокоиться об утилизации subWeb, если iam уже перенес spSite в оператор Using?

Edit:

Является ли хорошей идеей также вызывать сборщик мусора в этом сценарии?

Ответы [ 2 ]

6 голосов
/ 18 марта 2009

К сожалению, вы делаете. Проблема начинается со свойства SPSite.AllWebs. Свойство SPWeb.Web также небезопасно.

Прочтите этот очень подробный справочник ситуаций, когда вам нужно беспокоиться об удалении объектов SharePoint.

(я предлагаю добавить это в ваш шпаргалку SharePoint).

В результате я чувствую, что текущую объектную модель SharePoint нельзя безопасно использовать с синтаксисом LINQ.

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

Изменить: SPDisposeCheck - это консольное приложение командной строки, которое сканирует ваши сборки .NET и предупреждает вас о недоставленных ссылках на основе приведенных выше рекомендаций. Проверьте это.

http://code.msdn.microsoft.com/SPDisposeCheck

http://blogs.msdn.com/sharepoint/archive/2008/11/12/announcing-spdisposecheck-tool-for-sharepoint-developers.aspx

2 голосов
/ 01 апреля 2009

Техническим ответом на ваш исходный вопрос является квалифицированное «Нет»: все SPWeb объекты, открытые из SPSite, автоматически удаляются при удалении SPSite. Однако на практике хорошей идеей будет использовать SPWeb, как только вы закончите с ним, чтобы уменьшить нагрузку на память, особенно при работе с таким кодом, который открывает несколько SPWeb объектов.

Реализация этого безопасного поведения для LINQ на самом деле довольно проста в C #. Вы можете найти полную информацию в этой записи , но короткая версия заключается в том, что итератор C # может обработать для вас избавление. Используя мой AsSafeEnumerable() метод расширения, ваш код относительно безопасно написан так:

using (SPSite spSite = Utility.GetElevatedSite(_rootUrl))
{
    var sw = from SPWeb web in spSite.AllWebs.AsSafeEnumerable()
             where web.ServerRelativeUrl.ToLower() == path
             from SPWeb subWeb in web.Webs.AsSafeEnumerable()      
             select subWeb;
    foreach(SPWeb aSubWeb in sw)
    {
        // Do something
    }
}

Теперь результатом вашего запроса, который я назначил sw, является ленивый итератор типа IEnumerable<SPWeb>. При перечислении этого результата каждый SPWeb будет удален, когда перечислитель перейдет к следующему элементу. Это означает, что небезопасно использовать эту ссылку SPWeb или любой объект SP *, созданный из нее (SPList и т. Д.), Вне вашей петли foreach. Также sw было бы небезопасно для использования вне этого блока using, потому что SPWebCollections итератора будет привязан к теперь расположенному SPSite.

Тем не менее, такой код, который перечисляет все сети (дважды!), Чрезвычайно дорог. Почти наверняка есть более эффективный способ реализовать это, если только использовать spSite.AllWebs[path] вместо вашего from / where.

Что касается сбора мусора, эти объекты требуют удаления из-за неуправляемой памяти, выделенной для GC, о которой даже не знают.

Наконец, предостережение относительно вашей утилиты GetElevatedSite. Если вы используете RunWithElevatedPrivileges в своем вспомогательном методе для получения повышенного SPSite, существует ряд проблем, с которыми вы можете столкнуться, вернув SPSite из этого повышенного контекста. Если возможно, я бы предложил вместо этого использовать SPSite олицетворение - мой предпочтительный метод описан здесь .

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