none
Código para subir imagen tabla Access no funciona RRS feed

  • Pregunta

  • Hola:

    Con el código que pongo a continuación estoy intentando subir una imagen a una tabla Access a la que he añadido una columna de tipo varbinary.

    strSQL = "INSERT INTO Images (Image) VALUES (@BLOBData)"
    dbComando = New OleDbCommand(strSQL, dbConector)
    Dim strBLOBFilePath As String = strNombreArchivo
    Dim fsBLOBFile As New FileStream(strBLOBFilePath, FileMode.Open, FileAccess.Read)
    Dim bytBLOBData(CInt(fsBLOBFile.Length() - 1)) As Byte
    fsBLOBFile.Read(bytBLOBData, 0, bytBLOBData.Length)
    fsBLOBFile.Close()
    Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary, bytBLOBData.Length, ParameterDirection.Input, False, 0, 0, Nothing, DataRowVersion.Current, bytBLOBData)
    dbComando.Parameters.Add(prm)
    dbConector.Open()
    dbComando.ExecuteNonQuery()  '>>>>>>>>Aquí da Error de sintaxis en la instrucción INSERT INTO
    dbConector.Close()

    He repasado el código pero no consigo encontrar la causa de que en el executeNonQuery me depare ese error, parece como si no reconociera los parámetros que se han introducido al objeto Command.

    La imagen se sube perfectamente a un directorio de archivos en el server.

    Agradeceré a quien me pueda orientar para saber donde puede estar el error para subirla a la tabla Access.

    Saludos al grupo.


    miércoles, 29 de abril de 2015 21:35

Respuestas

  • Image es una palabra clave. Si lo tienes como nombre de campo debes ponerlo entr corchetes strSQL = "INSERT INTO Images ([Image]) VALUES (@BLOBData)"

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    jueves, 30 de abril de 2015 16:50
    Moderador
  • has probado lo siguiente?

    cambiar

    dbComando = New OleDbCommand(strSQL, dbConector)
     Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary)
    prm.Value = bytBLOBData
     dbComando.Parameters.Add(prm)

    por

    dbComando = New OleDbCommand(strSQL, dbConector)
    dbComando.Parameters.AddWithValue("@BLOBData", bytBLOBData)


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    viernes, 1 de mayo de 2015 1:11
    Moderador
  • Hola,

    Bueno, lo que yo he hecho es crearme una base de datos con tres campos Autonumerico (ID), Texto (Nombre) y OLE Object (Imagen) en Access 2010.

    Código hecho en 5 minutos, se puede mejorar mucho, es solo un ejemplo rapido:

    public partial class Form1 : Form
        {
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database1.accdb;Persist Security Info=False;");
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
                MemoryStream ms=new MemoryStream();
                Image img = new Bitmap("Goku.jpg");
    // guardo la imagen en la base de datos img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); Save("Goku", ms.ToArray()); // cargo la imagen el en picturebox pictureBox1.Image=LoadImg("Goku"); } Bitmap LoadImg(string Nombre) { OleDbCommand com = new OleDbCommand("Select Nombre,Imagen from ArchivoImagen where Nombre=@Nombre", con); com.Parameters.Add("@Nombre", OleDbType.VarChar); com.Parameters["@Nombre"].Value = Nombre; com.Connection.Open(); var reader=com.ExecuteReader(); reader.Read(); MemoryStream ms = new MemoryStream(); var arr=(byte[])reader[1]; ms.Write(arr, 0, arr.Length); com.Connection.Close(); return new Bitmap(ms); } void Save(string Nombre,byte[] Imagen) { OleDbCommand com = new OleDbCommand("Insert into ArchivoImagen (Nombre,Imagen) values (@Nombre,@Imagen)", con); com.Parameters.Add("@Nombre", OleDbType.VarChar); com.Parameters.Add("@Imagen", OleDbType.Binary); com.Parameters["@Nombre"].Value = Nombre; com.Parameters["@Imagen"].Value = Imagen; com.Connection.Open(); com.ExecuteNonQuery(); com.Connection.Close(); } }
    El código es C# Winforms, pero se puede adaptar muy fácilmente a asp.net

    Saludos,




    viernes, 1 de mayo de 2015 14:02

Todas las respuestas

  • hola

    >>estoy intentando subir una imagen a una tabla Access a la que he añadido una columna de tipo varbinary.

    pero en Ms Access no existe el varbinary como tipo de datos, este es de sql server

    entiendo que solo tienes estos tipos de datos imagen

    ----

    porque no definas mas corto el parametro

    Dim  bytBLOBData() As Byte = File.ReadAllBytes(strBLOBFilePath)
    
    Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary)
    prm.Value = bytBLOBData
    dbComando.Parameters.Add(prm)

    Nota: para usar la clase File valida tener definido el Imports System.IO

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina


    jueves, 30 de abril de 2015 3:41
  • Hola Leandro:

    He hecho las correcciones que me dices y el error persiste, siempre es el mismo, error en la instrucción INSERT INTO, pero no me da más explicaciones, ya digo que es como si no reconociera los parámetros de Command al sustituir los valores del INSERT.

                    Dim fsBLOBFile As New FileStream(strNombreArchivo, FileMode.Open, FileAccess.Read)
                    Dim bytBLOBData() As Byte = File.ReadAllBytes(strNombreArchivo)
                    fsBLOBFile.Read(bytBLOBData, 0, bytBLOBData.Length)
                    fsBLOBFile.Close()
                    strSQL = "INSERT INTO Images (Image) VALUES (@BLOBData)"
                    dbComando = New OleDbCommand(strSQL, dbConector)
                    Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary)
                    prm.Value = bytBLOBData
                    dbComando.Parameters.Add(prm)
                    dbConector.Open()
                    dbComando.ExecuteNonQuery()  '>>>>>>>>Aquí da Error de sintaxis en la instrucción INSERT INTO
                    dbConector.Close()

    Los campos los añado por código sql: alter table alter column y los valores que me deja poner son Binary o VarBinary, Longvarbinary no lo admite tampoco, y OLE OBJECT no lo reconoce.

    La bd de esta aplicación es de Access 2000 y el motor jet oledb 4.0.

    Un saludo.

    jueves, 30 de abril de 2015 7:59
  • hola

    si usas el File.ReadAllBytes() ya no necesitas el

    Dim fsBLOBFile As New FileStream(strNombreArchivo, FileMode.Open, FileAccess.Read)

    fsBLOBFile.Read(bytBLOBData, 0, bytBLOBData.Length)
    fsBLOBFile.Close()

    todo eso puedes quitarlo

    >>La bd de esta aplicación es de Access 2000 y el motor jet oledb 4.0.

    la tabla solo tiene un unico campo ?

    no evaluaste migrar a una db mas actualizada? digamos a sql server

    saludos


    Leandro Tuttini

    Blog
    MVP Profile
    Buenos Aires
    Argentina

    jueves, 30 de abril de 2015 11:07
  • Hola Leandro:

    Probaré a quitar lo que me dices, pero de todas formas ya he decidido migrar a sql server.

    Te diré si el cambio de la instrucción me da resultado, pero he probado muchos cambios y siempre dice error en la instrucción INSERT INTO.

    En caso de que lo consiga te lo diré.


    jueves, 30 de abril de 2015 15:38
  • Image es una palabra clave. Si lo tienes como nombre de campo debes ponerlo entr corchetes strSQL = "INSERT INTO Images ([Image]) VALUES (@BLOBData)"

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    jueves, 30 de abril de 2015 16:50
    Moderador
  • Gracias, Sergio.

    Últimamente yo también había sospechado de que Image fuera una palabra reservada y de hecho el mensaje de error ha cambiado desde que he cambiado el nombre Image por FileImage, ahora por primera vez dice que los tipos no coinciden.

    El código que me genera error de que no coinciden los tipos es éste, lo he repasado y no encuentro discrepancia, el campo es varbinary y el parámetro se supone que es un byte. He intentado hacer un debug write pero no sé como hacerlo con datos binarios.

                    Dim fsBLOBFile As New FileStream(strNombreArchivo, FileMode.Open, FileAccess.Read)
                    Dim bytBLOBData() As Byte = File.ReadAllBytes(strNombreArchivo)
                    strSQL = ""
                    strSQL = "INSERT INTO Images (FileImage) " & _
                        "VALUES " & _
                        "(@BLOBData)"
                    dbComando = New OleDbCommand(strSQL, dbConector)
                    Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary)
                    prm.Value = bytBLOBData
                    dbComando.Parameters.Add(prm)
                    dbConector.Open()
                    dbComando.ExecuteNonQuery()  '>>>>>>>>Aquí da Error de que no coinciden los tipos en la expresión de criterios
                    dbConector.Close()

    Repito que estoy con Access 2000 y con jet oledb 4 aunque migrando a sql server pero un código similar tendré que usar. Mi idea es luego con un handler extraer la imagen de la bd y mostrarla desde un src como si fuera una Url. El motivo es que quiero tener todos los datos encapsulados en la bd de cada sucursal, con las fotos en binario porque se trata de datos protegidos, pero estoy estudiando otras posibilidades como guardarlas en archivos binarios y no en archivos de imagen.

    Un saludo

    jueves, 30 de abril de 2015 21:11
  • Hola:

    Tras cambiar el campo "Image" por "FileImage" hemos comprobado que Image es una palabra reservada pues el comportamiento ha cambiado enseguida.

    Una vez hecho este cambio ha empezado a arrojar un error de que no coinciden los tipos en la expresión de criterios y se me ha ocurrido poner comillas simples en el value FileImage de la cadena SQL como si fuera un valor literal de cadena con lo que ha dejado de dar error, lo cual me ha sorprendido mucho porque en ningún código que he consultado se ponen comillas simples al valor binario al que luego se le agrega un parámetro en el command.

     strSQL = "INSERT INTO Images (FileImage) " & _
     "VALUES " & _
     "('@BLOBData')"

    Antes de dar por finalizado el tema me gustaría saber vuestra opinión, porque de momento no he visto el resultado, es decir, no he visto la foto que he insertado, solo se que el procedimiento ha llegado al final sin errores. Ahora me queda ver con código inverso si realmente la imagen está ahí.

    Un saludo.

    jueves, 30 de abril de 2015 22:07
  • has probado lo siguiente?

    cambiar

    dbComando = New OleDbCommand(strSQL, dbConector)
     Dim prm As New OleDbParameter("@BLOBData", OleDbType.VarBinary)
    prm.Value = bytBLOBData
     dbComando.Parameters.Add(prm)

    por

    dbComando = New OleDbCommand(strSQL, dbConector)
    dbComando.Parameters.AddWithValue("@BLOBData", bytBLOBData)


    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    viernes, 1 de mayo de 2015 1:11
    Moderador
  • Hola Sergio:

    Lo de ponerle comillas no funciona porque lo que copia es el literal que hay entre las comillas, por eso se completa falsamente el procedimiento.

    En cuanto a la solución que me dices, lo he probado pero vuelve a decir que no coinciden los tipos en la expresión de criterios, ya digo que es como si no reconociera los parámetros del Command. Todo esto en Access 2000 y motor jet oledb 4.0 que ya queda algo obsoleto.

    Por todo esto estoy migrando a SQL Server que entre otras cosas tiene un campo Imagen. Para mi un campo imagen es un dato más de la aplicación y es mejor que tener las imágenes dispersas en carpetas aunque pueda hacer una tabla con enlaces a carpetas que es otra posibilidad.

    Me queda la duda si una bd SQL Server con imágenes va a entorpecer el resto de la BD, he leído opiniones de todas clases.

    Un saludo.

    viernes, 1 de mayo de 2015 8:06
  • una solución que te propongo es realizar lo siguiente. Cambia el tipo de dato de tu campo a Memo creo que era ese que almacenaba cadenas muy largas. Y convertir la imagen a un string Base64 y guardarla. Luego a la hora de recuperar dicha imagen haces la inversa decodificas la cadena base64 y generas el array de bytes para cargar la imagen en algún control. Espero haberte dado pistas. No se cómo se comportará Access 2000 ya que como dices es bastante obsoleto.

    Si se solucionó tu consulta no olvides marcar la respuesta. Si te ayudó, vótala como útil. Saludos

    viernes, 1 de mayo de 2015 10:57
    Moderador
  • Hola,

    Bueno, lo que yo he hecho es crearme una base de datos con tres campos Autonumerico (ID), Texto (Nombre) y OLE Object (Imagen) en Access 2010.

    Código hecho en 5 minutos, se puede mejorar mucho, es solo un ejemplo rapido:

    public partial class Form1 : Form
        {
            OleDbConnection con = new OleDbConnection(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=Database1.accdb;Persist Security Info=False;");
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
                MemoryStream ms=new MemoryStream();
                Image img = new Bitmap("Goku.jpg");
    // guardo la imagen en la base de datos img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); Save("Goku", ms.ToArray()); // cargo la imagen el en picturebox pictureBox1.Image=LoadImg("Goku"); } Bitmap LoadImg(string Nombre) { OleDbCommand com = new OleDbCommand("Select Nombre,Imagen from ArchivoImagen where Nombre=@Nombre", con); com.Parameters.Add("@Nombre", OleDbType.VarChar); com.Parameters["@Nombre"].Value = Nombre; com.Connection.Open(); var reader=com.ExecuteReader(); reader.Read(); MemoryStream ms = new MemoryStream(); var arr=(byte[])reader[1]; ms.Write(arr, 0, arr.Length); com.Connection.Close(); return new Bitmap(ms); } void Save(string Nombre,byte[] Imagen) { OleDbCommand com = new OleDbCommand("Insert into ArchivoImagen (Nombre,Imagen) values (@Nombre,@Imagen)", con); com.Parameters.Add("@Nombre", OleDbType.VarChar); com.Parameters.Add("@Imagen", OleDbType.Binary); com.Parameters["@Nombre"].Value = Nombre; com.Parameters["@Imagen"].Value = Imagen; com.Connection.Open(); com.ExecuteNonQuery(); com.Connection.Close(); } }
    El código es C# Winforms, pero se puede adaptar muy fácilmente a asp.net

    Saludos,




    viernes, 1 de mayo de 2015 14:02
  • Hola:

    Probé una solución semejante a la que propone Sergio pero sin resultados o al menos el procedimiento no funcionó.

    En cuanto al código de Cybernoid, he cambiado la conexión a al motor ACE.OLEDB.12 y funciona con todo lo demás pero el error sigue siendo el mismo, no reconoce la cadena de conexión con parámetros en el command.

    De todas formas ya he decidido migrar todo a sql server pero me están surgiendo problemas nuevos a la hora de abrir las BD que expongo en otra pregunta.

    Saludos al grupo.

    domingo, 3 de mayo de 2015 18:37