Access
 sql >> база данни >  >> RDS >> Access

Групови вмъквания или актуализация за таблици с полета за прикачени файлове

От Access 2010 Access поддържа тип данни прикачени файлове, който на повърхността изглежда като удобна функция за съхранение на малки изображения или файлове. Въпреки това, бързо търсене в Google обикновено показва, че е най-добре да се избягват. Всичко това се свежда до факта, че типът данни за прикачени файлове всъщност е многозначно поле (MVF) и те идват с няколко проблема. От една страна, няма да можете да използвате заявки за вмъкване или актуализиране на няколко записа наведнъж. Всъщност всички таблици, които съдържат такъв тип данни, ви принуждават да правите много код и само поради тази причина избягваме да използваме такива типове данни нормално.

Има обаче проблем. Обичаме да използваме галерията с изображения и темите, като и двете зависят от системна таблица, MSysResources който за съжаление използва типовете данни за прикачени файлове. Това създаде проблем за управлението на ресурси в нашата стандартна библиотека, защото искаме да използваме MSysResources но не можем лесно да ги актуализираме или вмъкваме групово.

Типът данни за прикачени файлове (както и MVFs) ви принуждава да използвате програмиране „ред по-агонизиращ ред“, когато работите с поле MVF, това е полето с прикачени файлове, защото ще трябва да използвате LoadFromFile или SaveToFile методи. Microsoft има статия с примери за тези методи. По този начин трябва да взаимодействате с файловата система, когато добавяте нови записи. Не винаги е желателно във всички ситуации. Сега, ако копираме от една таблица в друга таблица, можем да избегнем прескачането на файловата система, като направим нещо като:

Dim SourceParentRs As DAO.Recordset2
Dim SourceChildRs As DAO.Recordset2
Dim TargetParentRs As DAO.Recordset2
Dim TargetChildRs As DAO.Recordset2
Dim SourceField As DAO.Field2

Set SourceParentRs = db.OpenRecordset("TableWithAttachmentField", dbOpenDynaset)
Set TargetParentRs = db.OpenRecordset("AnotherTableWithAttachmentField", dbOpenDynaset, dbAppendOnly)

Do Until SourceParentRs.EOF
  TargetParentRs.AddNew
  For Each SourceField In SourceParentRs.Fields
    If SourceField.Type <> dbAttachment Then
      TargetParentRs.Fields(SourceField.Name).Value = SourceField.Value
    End If
  Next

  TargetParentRs.Update 'Must save record first before can edit MVF fields
  TargetParentRs.Bookmark = TargetParentRs.LastModified
  Set SourceChildRs = SourceParentRs.Fields("Data").Value
  Set TargetChildRs = TargetParentRs.Fields("Data").Value
  Do Until SourcechildRs.EOF
    TargetChildRs.AddNew
    Const ChunkSize As Long = 32768
    Dim TotalSize As Long
    Dim Offset As Long

    TotalSize = SourceChildRs.Fields("FileData").FieldSize
    Offset = TotalSize Mod ChunkSize
    TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(0, Offset)
    Do Until Offset > TotalSize
      TargetChildRs.Fields("FileData").AppendChunk(SourceChildRs.GetChunk(Offset, ChunkSize)
      Offset = Offset + ChunkSize
    Loop
    TargetChildRs.Update
    SourceChildRs.MoveNext
  Loop
  TargetParentRs.Update
  SourceParentRs.MoveNext
Loop

Свети лупинг, батман! Това е много код, всичко само за копиране на прикачени файлове от една таблица в друга. Въпреки че не прескачаме файловата система, тя също е много бавна. Според нашия опит таблица с 1000 записа, съдържащи един прикачен файл, може да отнеме минути само за обработка. Сега това е доста огромен, като се има предвид размерът. Масата с приставките не е толкова голяма. Всъщност, нека направим експеримент. Нека видим какво ще се случи, ако копирам и поставям чрез листа с данни:

Така че копирането и поставянето става практически мигновено. Очевидно кодът, използван при поставяне, не е същият код, който бихме използвали във VBA. Въпреки това, ние силно вярваме, че ако можем да го направим интерактивно, можем да го направим и във VBA. Можем ли да повторим скоростта на интерактивното поставяне във VBA? Отговорът се оказва да, можем!

Ускорете с.... XML?

Изненадващо методът, който осигурява най-бързия начин за копиране на данни, включително прикачени файлове, е чрез XML файлове. Ще призная, че не посягам към XML файлове, освен като заобиколно решение за ограничения. Средно XML файловете са относително бавни спрямо други файлови формати, но в този случай XML има едно огромно предимство; няма проблем с описанието на MVF. Нека създадем XML файл и да проучим възможностите, които получаваме с импортирането/експортирането на XML файл.

След обичайния диалогов прозорец на съветника за експортиране, за да зададете пътя за запазване на XML файла, ще получим диалогов прозорец като този:

Ако след това щракнем върху бутона „Още опции...“, вместо това получаваме този диалогов прозорец:

От този диалог виждаме още няколко улики за това какво е възможно; а именно:

  • Имаме опцията да експортираме цялата таблица или само подмножество от таблицата чрез прилагане на филтър
  • Можем да трансформираме XML изхода.
  • Можем да опишем схемата в допълнение към съдържанието на таблицата.

Намирам, че е най-добре да вградите схемата; по подразбиране е да се експортира, но като отделен файл. Това обаче може да бъде податливо на грешки и те могат да забравят да включат XSD файла с XML файла. Това може да се промени чрез показания раздел на схемата:

Нека приключим с експортирането му и да разгледаме бързо данните на получения XML файл.

Имайте предвид, че прикачените файлове са описани в Данни поддървото и съдържанието на файла е кодирано с база 64. Нека опитаме да импортираме XML файла. След като преминем през съветника за импортиране, ще получим този диалогов прозорец:

Обърнете внимание на следните функции:

  • Както при експортирането, ние имаме опцията да трансформираме XML.
  • Можем да контролираме дали да импортираме структурата, данните или и двете

Ако след това приключим с импортирането на XML файла, ще открием, че той е също толкова бърз, колкото и операцията copy’paste, която направихме.

Вече знаем, че има по-добър път за копиране на няколко записа с прикачени файлове. Но в тази ситуация искаме да направим това програмно, а не интерактивно. Можем ли да направим същото, което направихме току-що? Отново отговорът е да. Има няколко начина да направите едно и също нещо, но мисля, че най-лесният метод е да използвате 3-те нови метода, които бяха добавени към Application обект от Access 2010:

  • ExportXML метод
  • TransformXML метод
  • ImportXML метод

Имайте предвид, че ExportXML методът поддържа експортиране от различни обекти. Въпреки това, тъй като целта тук е да можем да копираме или актуализираме масово записите на таблица с полета за прикачени файлове, най-добрият тип обект, който да използваме, е запазена заявка. Със запазена заявка можем да контролираме кои редове да бъдат вмъкнати или актуализирани и също така можем да оформим изхода. Ако погледнете дизайна на схемата на MSysResources таблица по-долу:

Има потенциален проблем. Всеки път, когато използваме теми или изображения, препращаме към елемента по име, а не по идентификатор. Въпреки това, Име колоната не е уникална и не е първичен ключ на таблицата. Следователно, когато добавяме или актуализираме записи, искаме да съвпадаме в Име колона, а не Id колона. Това означава, че когато експортираме, вероятно не трябва да включваме Id колона и трябва да експортираме само уникалния списък на Име за да гарантирате, че ресурсите няма да преминат внезапно от „Open.png“ към „Close.png“ или нещо глупаво.

След това ще създадем заявка, която да действа като източник на записите, които искаме да импортираме в MSysResources маса. Нека започнем с този SQL, само за да демонстрираме филтрирането до подмножество от записи:

SELECT e.Data, e.Extension, e.Name, e.Type
FROM Example AS e
WHERE e.Name In ("blue","red","green");

След това ще го запишем като qryResourcesExport . След това можем да напишем VBA код за експортиране на XML:

Application.ExportXML _
  ObjectType:=acExportQuery, _
  DataSource:="qryResourcesExport", _
  DataTarget:="C:\Path\to\Resources.xml", _
  OtherFlags:=acEmbedSchema

Това емулира експорта, който първоначално направихме интерактивно.

Ако обаче импортираме получения XML, имаме възможност само да добавим данни към съществуваща таблица. Не можем да контролираме в коя таблица ще се добави; той ще намери таблица или таблица със заявка със същото име (напр. qryResourcesExport и добавете записи към тази заявка. Ако заявката може да се актуализира, тогава няма проблем и тя ще се вмъкне в Пример на която се основава заявката. Но какво ще стане, ако изходната заявка, която използваме, не може да се актуализира или може да не съществува? И в двата случая няма да можем да импортираме XML файла такъв, какъвто е. Може или да не успее да импортира, или в крайна сметка да създаде нова таблица с име qryResourcesExport което не ни помага. А какво да кажем за случая на копиране на данни от Пример към MSysResources ? Не искаме да добавяме данни към Пример таблица.

Това е мястото, където TransformXML методът идва на помощ. Пълна дискусия за това как да напишете XML трансформация е извън обхвата, но трябва да можете да намерите достатъчно ресурси за това как да напишете XSLT стилова таблица, за да опишете трансформацията. Има няколко онлайн инструмента, които можете да използвате и за валидиране на вашия XSLT. Ето едно. За простия случай, в който просто искаме да контролираме в коя таблица XML файлът трябва да добави записите, можете да започнете с този XSLT файл. След това можете да стартирате следния VBA код:

Application.TransformXML _
  DataSource:="C:\Path\to\Resources.xml", _
  TransformSource:="C:\Path\to\ResourcesTransform.xslt", _
  OutputTarget:="C:\Path\to\Resources.xml", _
  WellFormedXMLOutput:=True, _
  ScriptOption:=acEnableScript

Можем да заменим оригиналния XML файл с трансформирания XML файл, който сега ще се вмъкне в MSysResources таблица, а не в (евентуално несъществуваща заявка/таблица) qryResourcesExport .

След това трябва да се справим с актуализациите. Защото всъщност добавяме нови записи и MSysResources таблицата няма ограничения за дублиращите се имена, трябва да гарантираме, че всички съществуващи записи със същите имена първо ще бъдат изтрити. Това може да се постигне чрез написване на еквивалентна заявка, както следва:

DELETE FROM MSysResources AS r
WHERE r.Name In ("blue","red","green");

след това първо го стартирайте, преди да стартирате VBA кода:

Application.ImportXML DataSource:="C:\Path\to\Resources.xml", ImportOptions:=acAppendData

Тъй като XML файлът е трансформиран, ImportXML сега методът ще вмъкне данните в MSysResources таблица, а не оригиналната заявка, която използвахме с ExportXML метод. Уточняваме, че трябва да добавя данни в съществуваща таблица. Ако обаче таблицата не съществува, тя ще бъде създадена.

И с това постигнахме масова актуализация/вмъкване на таблицата с поле за прикачени файлове, което е много по-бързо в сравнение с оригиналния VBA код за набор от записи и дете. Надявам се това да помогне! Освен това, ако имате нужда от помощ при разработването на приложения на Access, не се колебайте да се свържете с нас!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Microsoft OLE DB не се препоръчва! Да живее ADO!

  2. Официалният технически блог на Microsoft Access вече е онлайн!

  3. Как да навигирате в отварящото работно пространство на Access 2019

  4. Как да отворите таблица в Design View в Microsoft Access

  5. Криптиране на база данни:3-те типа и защо са ви необходими