Сохранение изображения в поле вложения в базе данных Access

Я пишу приложение VB, в котором мне нужно сохранить изображение в базе данных. Пользователь выбирает изображение на своем компьютере, что дает мне путь в виде строки. Вот моя попытка, однако я получаю сообщение об ошибке «Запрос INSERT INTO не может содержать многозначное поле».

Вот мой код:

Dim buff As Byte() = Nothing
Public Function ReadByteArrayFromFile(ByVal fileName As String) As Byte()
    Dim fs As New FileStream(fileName, FileMode.Open, FileAccess.Read)
    Dim br As New BinaryReader(fs)
    Dim numBytes As Long = New FileInfo(fileName).Length
    buff = br.ReadBytes(CInt(numBytes))
    Return buff
End Function

Sub ....
    Dim connImg As New OleDbConnection
    Dim sConnString As String
    Dim cmdImg As New OleDbCommand

    sConnString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & My.Settings.DB & ";Persist Security Info=False;"
    connImg = New OleDbConnection(sConnString)
    connImg.Open()
    cmdImg.Connection = connImg
    cmdImg.CommandType = CommandType.Text

    If d.slogo <> "" Then
        cmdImg.CommandText = "INSERT INTO Logo ( refId, [type], [img] ) VALUES(@refId, @type, @imgBinary)"
        cmdImg.Parameters.Add("@refId", OleDbType.Double).Value = refId
        cmdImg.Parameters.Add("@type", OleDbType.Double).Value = 0
        cmdImg.Parameters.Add("@imgBinary", OleDbType.VarBinary).Value = ReadByteArrayFromFile(PathToImage)
        cmdImg.ExecuteNonQuery()
    End If
    ....
End Sub

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

Спасибо за любую помощь!


person Michael    schedule 12.09.2013    source источник
comment
Не могли бы вы поделиться схемой вашей таблицы и любых связанных таблиц?   -  person websch01ar    schedule 12.09.2013
comment
Извините, я не уверен на 100%, что вы ищете, но я сделаю все возможное: в этой таблице Logo есть 3 поля. refId и введите как Numbers. img как вложение. refId — это просто идентификатор, который ссылается на productId в другой таблице. К каждому продукту будут прикреплены разные изображения (например, реклама и обложка в журнале). Сейчас их всего 2, но со временем их количество будет увеличиваться. Комбинация refId и type является первичным ключом.   -  person Michael    schedule 12.09.2013
comment
Проблема, с которой вы столкнулись, связана с refID, а не с изображениями. Я давно не занимался разработкой для Access, но погуглил и нашел способы обойти этот многозначный столбец.   -  person websch01ar    schedule 12.09.2013
comment
Если я запускаю запрос без поля img, он работает нормально. Я не думаю, что это refID.   -  person Michael    schedule 12.09.2013


Ответы (3)


Как вы уже поняли, вы не можете использовать оператор SQL для вставки файлов в поле Attachment в базе данных Access. Вы должны использовать метод LoadFromFile() объекта ACE DAO Field2. Следующий код С# работает для меня. Он взят из записи блога Office здесь.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Access.Dao;

namespace daoConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // This code requires the following COM reference in your project:
            //
            // Microsoft Office 14.0 Access Database Engine Object Library
            //
            var dbe = new DBEngine();
            Database db = dbe.OpenDatabase(@"C:\__tmp\testData.accdb");
            try
            {
                Recordset rstMain = db.OpenRecordset(
                        "SELECT refId, img FROM Logo WHERE refId = 1", 
                        RecordsetTypeEnum.dbOpenDynaset);
                if (rstMain.EOF)
                {
                    // record does not already exist in [Logo] table, so add it
                    rstMain.AddNew();
                    rstMain.Fields["refId"].Value = 1;
                }
                else
                {
                    rstMain.Edit();
                }
                // retrieve Recordset2 object for (potentially multi-valued) [img] field
                //     of the current record in rstMain
                Recordset2 rstAttach = rstMain.Fields["img"].Value;
                rstAttach.AddNew();
                Field2 fldAttach = 
                        (Field2)rstAttach.Fields["FileData"];
                fldAttach.LoadFromFile(@"C:\__tmp\testImage.jpg");
                rstAttach.Update();
                rstAttach.Close();
                rstMain.Update();
                rstMain.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }
}
person Gord Thompson    schedule 12.09.2013

Я сделал то же самое на основе приведенного выше кода и записи в блоге из здесь.

Вот мой код vb.net, который позволяет мне делать OpenFileDialog и множественный выбор, и функция отлично справляется с хранением нескольких файлов. Хотя мне пришлось добавить ссылку на мой проект для библиотеки объектов ядра базы данных Microsoft Office 15.0 Access, чтобы заставить его работать правильно. Я думаю, вы также можете перейти на 12.0 или 14.0.

Private Sub AddAttachment(ByVal Files() As String)
    Const Caller = "AddAttachment"
    Dim dbe = New Microsoft.Office.Interop.Access.Dao.DBEngine()
    Dim db As Microsoft.Office.Interop.Access.Dao.Database
    db = dbe.OpenDatabase(dbPath)
    Try
        Dim rstMain As Microsoft.Office.Interop.Access.Dao.Recordset
        rstMain = db.OpenRecordset("SELECT ID, fieldName FROM tableName WHERE ID = " + (dt.Rows(currentRow).Item("ID").ToString), Microsoft.Office.Interop.Access.Dao.RecordsetTypeEnum.dbOpenDynaset)
        If (rstMain.EOF) Then
            rstMain.AddNew()
            rstMain.Fields("ID").Value = 1
        Else
            For Each value As String In Files
                rstMain.Edit()
                Dim rstAttach As Microsoft.Office.Interop.Access.Dao.Recordset2
                rstAttach = rstMain.Fields("ATTACHMENTS").Value
                rstAttach.AddNew()
                Dim fldAttach As Microsoft.Office.Interop.Access.Dao.Field2
                fldAttach = rstAttach.Fields("FileData")
                fldAttach.LoadFromFile(value)
                rstAttach.Update()
                rstAttach.Close()
            Next
            rstMain.Update()
            rstMain.Close()
        End If

    Catch ex As Exception
        If Err.Number <> 3820 Then
            MsgBox(ex.Message)
        Else
            MsgBox("File of same name already attached", MsgBoxStyle.Critical, "Cannot attach file" & Caller)
            MessageBox.Show(ex.Message)
        End If

    End Try
End Sub

Сейчас я работаю над функциями RemoveAttachments и сохранения файлов из поля вложений. Я опубликую их здесь позже.

person Tim Ryder    schedule 17.12.2013

Еще одна вещь, чтобы добавить к этому. Если ваша база данных зашифрована, вам нужно будет добавить команду OpenDatabase.

Это код, который я использовал в C#, но код VB.NET будет очень похож. db = dbe.OpenDatabase (dbPath, false, false, «MS Access; PWD = пароль»);

Мне потребовались годы, чтобы попытаться отследить это самостоятельно, и я попытаюсь разбить различные части метода. Статью MSDN для него можно найти здесь< /а>.

1-й аргумент: dbPath, это то же самое, что и в исходном сообщении. Расположение и имя файла базы данных, которую вы хотите открыть.

2-й аргумент: неверно. Это аргумент true/false, если true открывает базу данных в монопольном режиме. Так что только эта единственная программа может его использовать. В большинстве случаев это должно быть ложным. Используйте эксклюзивный режим только в случае необходимости.

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

4-й аргумент: устанавливает определенные свойства открытия базы данных. В таком случае. В нем сказано установить для свойства Microsoft Access «PWD» значение «пароль». В этом параметре свойства указано, что метод должен открыть зашифрованную базу данных, используя пароль «пароль». Конечно, вам нужно будет изменить «пароль» на любой фактический пароль базы данных, который нужно открыть, но я некоторое время искал это.

Надеюсь, это поможет.

person Bazag    schedule 12.06.2015
comment
Не могли бы вы уточнить свой ответ, добавив немного больше описания решения, которое вы предоставляете? - person abarisone; 12.06.2015