GRAVAR DADOS VARBINARY(MAX) GRANDES

LUIS.HERRERA 03/07/2014 11:49:43
#439326
Amigos bom dia.
No SQL Server 2008 R2 Express, eu criei 2 bancos, um principal com todas as tabelas e um View para consultar e inserir dados na única tabela do banco 2, usado só para arquivos binários (em função da capacidade do express).

Tudo funciona perfeitamente, porém para arquivos bem pequenos, pois ao tentar incluir um arquivo de apenas 256kb deu erro 8152 (dados truncados) e não gravou.
O limite do campo Varbinary(Max) é de 2 GB, porém ao tentar passar o arquivo como parâmetro SQL, surge a mensagem que o limite máximo é 8 mil bytes apenas.

Como resolver isso, já que o SQL aceita 2 GB por campo, mas não se pode passar uma arquivo com mais de 256 kb ?

testei select @@TEXTSIZE e retornou o tamanho de 2147483647 (que é o limite de 2GB), então porque não grava?
O código que uso para passar o arquivo em array de bytes é:

  
....
[txt-color=#e80000]cmd.Parameters.Add([Ô]@ARQUIVOBINARIO[Ô], SqlDbType.VarBinary);[/txt-color]
cmd.Parameters[[Ô]@ARQUIVOBINARIO[Ô]].Value = myArquivoBinario.ARQUIVOBINARIO;

//grava novo documento digital no banco
myIDNovoArquivo = (Int32)cmd.ExecuteScalar(); // recebe o novo ID do


O erro surge na linha em vermelho que deveria receber qualquer arquivo.

ALGUéM saberia como resolver isso?????
RO.DRIGOSG 03/07/2014 12:08:43
#439328
Luis,

Faz um teste, em vez de você utilizar o datatype [Ô]SqlDbType.VarBinary[Ô] use o [Ô]SqlDbType.SqlFileStream[Ô]. Não lembro se é SqlDbType ou só SqlTypes.
Veja se resolve o problema.
LUIS.HERRERA 03/07/2014 12:43:35
#439330
Rodrigo eu tentei, mas não existe SqlFileStream dentro de SqlDbType e também não existe SqlTypes.
Será que existe isso? Tem que incluir algum using ?

Tentei trocar o campo de Varbinary(Max) para Image e até setando o tamanho máximo, mas deu o mesmo erro.
cmd.Parameters.Add([Ô]@ARQUIVOBINARIO[Ô], SqlDbType.Image, 2147483647);

Acho que o problema está no cmd da conexão ao passar o parâmetro ao SQL, parece que o parâmetro é que limita o tamanho do dado a ser enviado ao banco, independente do limite que o campo aceite.

No código C#, eu fiz o Stream para ler o arquivo do Disco, para reduzir o tamanho e não sobrecarregar o banco eu ZIPO ele primeiro e só depois passo o array de bytes para o SQL, mas não funciona mesmo, só com arquivos inferiores a 8 Kb.

Não uso o stream do próprio SQL Server, pois para isso teria de mudar totalmente o código atual. Além disso tem de configurar o SQL Server para aceitar o Stream que não é ativado por padrão. Nem sei direito todos os passos que seriam necessários para isso e se a versão Express funciona normalmente.
GUIMORAES 03/07/2014 13:49:54
#439331
Resposta escolhida
Tenta assim.

cmd.Parameters.Add([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
LUIS.HERRERA 03/07/2014 14:48:07
#439336
Guimoraes vamos lá...
Sua instrução funcionou só depois que alterei para:
cmd.Parameters.AddWithValue([Ô]@imagem[Ô], arquivoBinario.Length).Value = arquivoBinario;
Pois a sintaxe sugerida com Add é obsoleta na versão 2008 do SQL.

Porém após gravar os dados, ao recuperá-los no meu aplicativo, não consigo mais abrir o arquivo gravado, pois parece que o formato usado na gravação ficou diferente do ArraysByte que era enviado inicialmente. O que ocorreu com os dados no meu arquivoBinario ao ser gravado no banco?

Como posso recuperá-los corretamente?

RO.DRIGOSG 03/07/2014 14:48:57
#439337
Luis,

Tenta também com o [Ô]Text[Ô]
LUIS.HERRERA 03/07/2014 14:58:47
#439338
Rodrigo não entendi, que Text é esse? Estou passando uma matriz de Bytes[]

Guimoraes, Agora funcionou (VIVA!!!!!!). Eu cometi um erro, nos testes que estava fazendo para corrigir, e só agora reparei. Funcionou direitinho.
Muito obrigado amigo.
RO.DRIGOSG 03/07/2014 15:10:56
#439339
Segue EXEMPLO de como salvar anexos, acho que com isso vc consegue agora:

Obs.: Para o comando funcionar, o arquivo a ser transferido para o SQL, tem que estar em um servidor que o SQL reconheça, isso é muito importante.

VB.NET

No form de Salvar o Anexo:

 Private Sub cmdAnexo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdAnexo.Click

Dim dr As DialogResult = Me.ofdAnexo.ShowDialog()

[ô]Define as propriedades do controle OpenFileDialog
Me.ofdAnexo.Multiselect = False
Me.ofdAnexo.Title = [Ô]Selecionar Anexos[Ô]
ofdAnexo.InitialDirectory = [Ô]C:\[Ô]
ofdAnexo.Filter = [Ô]Todos os Arquivos (*.*)|*.*[Ô]
ofdAnexo.CheckFileExists = True
ofdAnexo.CheckPathExists = True
ofdAnexo.FilterIndex = 2
ofdAnexo.RestoreDirectory = True
ofdAnexo.ReadOnlyChecked = True
ofdAnexo.ShowReadOnly = True

If dr = System.Windows.Forms.DialogResult.OK Then

[ô]*** Le os arquivos selecionados caso a propriedade Multselect seja True

[ô]For Each file As [String] In ofdAnexo.FileNames
[ô] txtArquivo.Text += file
[ô] txtArquivo.Tag += ofdAnexo.SafeFileName
[ô]Next
txtArquivo.Text = ofdAnexo.FileName
txtArquivo.Tag = ofdAnexo.SafeFileName

End If

End Sub


Função para Salvar o anexo:

Public Function sp_Anexo(ByVal pstrOpcao As String, ByVal clsAnex As clsAnexo) As String

Dim sb As New System.Text.StringBuilder

Select Case pstrOpcao

Case [Ô]SALVAR[Ô]
sb.Append([Ô]INSERT INTO HelpDesk_Imagem (ID_Chamado, Descricao, Arquivo)[Ô])
sb.Append([Ô] SELECT [Ô])
sb.Append(clsAnex.pID_Chamado & [Ô] AS ID_Chamado[Ô])
sb.Append([Ô],[ô][Ô] & clsAnex.pDescricao & [Ô][ô] AS Descricao[Ô])
[ô]sb.Append([Ô], * FROM OPENROWSET (BULK [ô]\\data3\Arquivos \HelpDesk\Imagem_Temp\MVREGCLEAN.txt[ô], SINGLE_BLOB) AS Arquivo[Ô])
sb.Append([Ô], * FROM OPENROWSET (BULK [ô][Ô] & clsAnex.pAnexo & [Ô][ô], SINGLE_BLOB) AS Arquivo[Ô])

Case [Ô]GRIDANEXOS[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] *[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Chamado = [Ô] & clsAnex.pID_Chamado)

Case [Ô]BAIXARANEXO[Ô]
sb.Append([Ô]SELECT[Ô])
sb.Append([Ô] Descricao[Ô])
sb.Append([Ô] ,Arquivo[Ô])
sb.Append([Ô] FROM[Ô])
sb.Append([Ô] HelpDesk_Imagem[Ô])
sb.Append([Ô] WHERE[Ô])
sb.Append([Ô] ID_Imagem = [Ô] & clsAnex.pID_Imagem)

End Select

Return sb.ToString()

End Function


Função para baixar e Salvar o anexo em um diretório:

 Private Sub sSalvaArquivo()

Dim strQuery As String
Dim strNome As String
Dim ds As New DataSet
ds.Dispose()

Try

objConexaoImagens.AbreConexao()

For Each grdAnex As DataGridViewRow In grdAnexos.Rows
If grdAnex.Cells(edgvSupervisor.CheckBox).Value = True Then
objclsAnexo.pID_Imagem = grdAnex.Cells(edgvAnexos.ID_Imagem).Value

strQuery = objclsAnexo.fPesquisa([Ô]BAIXARANEXO[Ô])
ds = New DataSet([Ô]Anexos[Ô])
ds.Dispose()
ds = objConexaoImagens.AbreDataSet(strQuery, [Ô]Anexos[Ô])

Dim MyData() As Byte = New Byte(0) {}
Dim myRow As DataRow = ds.Tables([Ô]Anexos[Ô]).Rows(0)

strNome = myRow([Ô]Descricao[Ô]).ToString
MyData = CType(myRow([Ô]Arquivo[Ô]), Byte())

Using stream = New FileStream(txtCaminho.Text & [Ô]\[Ô] & strNome, FileMode.Create, FileAccess.Write)
stream.Write(MyData, 0, Convert.ToInt32(MyData.Length))
End Using

End If
Next grdAnex

Call frmMsgBox.Show([Ô]Arquivo(s) salvo(s) com sucesso.[Ô], MsgBoxStyle.Information, Me.Text)

Catch ex As Exception
MsgBox(ex.Message)

Finally
objConexaoImagens.FechaConexao()

End Try

End Sub
LUIS.HERRERA 03/07/2014 15:44:41
#439340
Guimoraes, desculpe reabrir o post, mas após fazer alguns testes o problema voltou a ocorrer, esquisito isso.

Fiz o teste com o arquivo 256kb, gravou, fiz com um arquivo 2 MB, gravou, fiz com um arquivos 6 MB gravou, mas ao tentar um de 7,5 MB deu o mesmo erro.

Que coisa [Ô]Doida[Ô], alguma idéia?


Rodrigo obrigado pelo código, só que uso C#. Já tenho toda a rotina pronta, eu leio o arquivo do disco em FileStream, depois compacto ele ZIp e por último passo o array byte[] desse ZIP para gravar no banco, o processo depois é inverso. Mas não entendo o porque limitar o tamanho do arquivo enviado. Agora está em mais de 7,5 MB. Eu até vou fazer uma rotina para testar o tamanho do arquivo e avisar ao usuário, estou até pensando em restringir esse tamanho a 1 MB, mas não vejo lógica nessa limitação ou problema da gravação, por isso quero resolver.

Obrigado
GUIMORAES 03/07/2014 16:18:28
#439341
Luiz, seguinte, no meu banco de dados eu utilizo tipo BLOB, não sei se existe esta tipagem no sql server.
Acredito que o erro está ocorrendo pois o tamanho do arquivo é grande, e isto vem em contrapartida a tipagem que você definiu.

Só para você ter uma ideia, quando crio uma tabela com o tipo blob no firebird, defino o tamanho dela, como este exemplo:

CREATE TABLE TESTE (
IMAGEM BLOB SEGMENT SIZE 4096);

O 4096 é o tamanho máximo do campo, se exceder, retornará erro.

A solução mais simples é criar um novo arquivo com o tamanho limitado, ex: imagem em 800x600 na extensão jpg.
Você também pode definir o tamanho do arquivo que o usuário pode carregar, agora é só usar a criatividade.
RO.DRIGOSG 03/07/2014 16:23:34
#439342
Luiz,

Será que a limitação não é por causa da versão Express??? Nessa rotina que eu te enviei, não encontrei limite de tamanho. Eu fiz um sistema de HelpDesk para uma empresa e eles tinha problemas justamente com o tamanho do arquivo e com essa rotina tudo foi solucionado. Faça o seguinte.

1 - No SQL mesmo, insira o código abaixo:

CREATE TABLE dbo.HelpDesk_Imagem
(
ID_Imagem int NOT NULL IDENTITY (1, 1),
Descricao varchar(50) NOT NULL,
Arquivo varbinary(MAX) NOT NULL
) ON [PRIMARY]
TEXTIMAGE_ON [PRIMARY]
GO

ALTER TABLE dbo.HelpDesk_Imagem ADD CONSTRAINT
PK_HelpDesk_Imagem PRIMARY KEY CLUSTERED
(
ID_Imagem
) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO


2 - Faça o Insert manualmente também:

INSERT INTO HelpDesk (ID_Chamado, Descricao, Arquivo)
SELECT
1 AS ID_Chamado
,[ô]Teste[ô] AS Descricao
, * FROM OPENROWSET (BULK [ô]\\data3\Arquivos \HelpDesk\Imagem_Temp\MVREGCLEAN.txt[ô], SINGLE_BLOB) AS Arquivo

Obs.: No lugar do caminho do BULK, use o caminho desse arquivo que vc não esta conseguindo salvar no banco. Lembrando que é o caminho onde o SQL consegue enxergar( seu servidor).

Se isso não funcionar, vamos saber que é limitação do banco de dados Express. Agora, se funcionar, você vai ter que alterar a sua rotina de [Ô]salvamento[Ô] para algo do tipo.
Página 1 de 2 [11 registro(s)]
Tópico encerrado , respostas não são mais permitidas