linq submitchanges не хватает памяти - PullRequest
1 голос
/ 25 ноября 2010

У меня есть база данных с около 180 000 записей.Я пытаюсь прикрепить файл PDF к каждой из этих записей.Каждый PDF-файл имеет размер около 250 КБ.Однако примерно через минуту моя программа начинает занимать около 1 ГБ памяти, и мне приходится ее останавливать.Я попытался сделать это так, чтобы ссылка на каждый объект linq удалялась после его обновления, но это, похоже, не помогает.Как я могу уточнить ссылку?

Спасибо за вашу помощь

Private Sub uploadPDFs(ByVal args() As String)
    Dim indexFiles = (From indexFile In dataContext.IndexFiles
                     Where indexFile.PDFContent = Nothing
                     Order By indexFile.PDFFolder).ToList
    Dim currentDirectory As IO.DirectoryInfo
    Dim currentFile As IO.FileInfo
    Dim tempIndexFile As IndexFile

    While indexFiles.Count > 0
        tempIndexFile = indexFiles(0)
        indexFiles = indexFiles.Skip(1).ToList
        currentDirectory = 'I set the directory that I need
        currentFile = 'I get the file that I need
        writePDF(currentDirectory, currentFile, tempIndexFile)
    End While
End Sub

Private Sub writePDF(ByVal directory As IO.DirectoryInfo, ByVal file As IO.FileInfo, ByVal indexFile As IndexFile)
    Dim bytes() As Byte
    bytes = getFileStream(file)
    indexFile.PDFContent = bytes
    dataContext.SubmitChanges()
    counter += 1
    If counter Mod 10 = 0 Then Console.WriteLine("     saved file " & file.Name & " at " & directory.Name)
End Sub


Private Function getFileStream(ByVal fileInfo As IO.FileInfo) As Byte()
    Dim fileStream = fileInfo.OpenRead()
    Dim bytesLength As Long = fileStream.Length
    Dim bytes(bytesLength) As Byte

    fileStream.Read(bytes, 0, bytesLength)
    fileStream.Close()

    Return bytes
End Function

Ответы [ 3 ]

4 голосов
/ 25 ноября 2010

Я предлагаю вам выполнить это партиями, используя Take ( перед вызовом ToList) для обработки определенного количества элементов за раз. Прочитайте (скажем) 10, установите PDFContent на все из них, позвоните SubmitChanges и затем начните снова. (Я не уверен, нужно ли вам начинать с нового DataContext в этот момент, но это может быть самым чистым.)

Кроме того, ваш код для чтения содержимого файла нарушается, по крайней мере, двумя способами - но было бы проще просто использовать File.ReadAllBytes во-первых.

Кроме того, ваш способ постепенного сокращения списка действительно неэффективен - после получения 180 000 записей вы создаете новый список с 179 999 записями, затем еще один с 179 998 записями и т. Д.

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

OK. Чтобы использовать наименьший объем памяти, мы должны обновить текст данных в блоках. Я поместил пример кода ниже. Могут быть ошибки синтаксиса, поскольку я использую блокнот для его ввода.

    Dim DB as YourDataContext = new YourDataContext
    Dim BlockSize as integer = 25
    Dim AllItems = DB.Items.Where(function(i) i.PDFfile.HasValue=False)

    Dim count = 0
    Dim tmpDB as YourDataContext = new YourDataContext


While (count < AllITems.Count)

    Dim _item = tmpDB.Items.Single(function(i) i.recordID=AllItems.Item(count).recordID)
    _item.PDF = GetPDF()

    Count +=1

    if count mod BlockSize = 0 or count = AllItems.Count then
        tmpDB.SubmitChanges()
         tmpDB =  new YourDataContext
           GC.Collect()
    end if

End While

Для дальнейшей оптимизации скорости вы можете получить идентификаторы записи в массив из allitems как анонимный тип и установить DelayLoading для этого поля PDF.

0 голосов
/ 25 ноября 2010

Установлено ли для DataContext значение ObjectTrackingEnabled, равное true (значение по умолчанию)? Если это так, то он будет пытаться вести учет практически всех данных, к которым он прикасается, что не позволяет сборщику мусора собирать какие-либо из них.

Если это так, вы сможете исправить ситуацию, периодически утилизируя DataContext и создавая новый, или отключая отслеживание объектов.

...