Problemas na criação dos Parâmetros de um Objeto TDBxCommand
Pessoal,
Estou com o seguinte problema: Criei um método tendo como parâmetros um Texto contendo o código SQL a ser executado por um objeto TDBXCommand e outro parâmetro do tipo Variant onde passo um array com os valores dos parâmetros do SQL. O problema acontece é que passo o SQL (com os caracteres "?") com parâmetros e na hora de atribuir os valores o Objeto TDBXCommand não criou os respectivos parâmetros.
A seguir estão os códigos do Método e sua chamada:
//O Método:
function TAppDataBaseService.ExecuteSQLCommand(ASQLStm: String; args: Variant): Boolean;var FCommand: TDBXCommand; AResult: Boolean; i: Integer;begin AResult := False; if not GetSessionConnection.Connected then GetSessionConnection.Open;
try FCommand := GetSessionConnection.DBXConnection.CreateCommand;
FCommand.CommandType:=TDBXCommandTypes.DbxSQL;
FCommand.Text := ASQLStm;
FCommand.Prepare;
if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do FCommand.Parameters.Parameter[i].Value.AsVariant := args[i];
FCommand.ExecuteUpdate;
AResult := True; finally FreeAndNil(FCommand); Result := AResult; end;end;
//A Chamada:
DataBaseConnectionService.ExecuteSQLCommand ('INSERT INTO tb_teste(id, nome, idade, datanasc) VALUES ( ? , ? , ? , ? )', varArrayof([ID, Name, Idade, DataNasc]));
Não sei por que motivo o TDBXCommand (Objeto FCommand) não cria os parâmetros. Desde já agradeço a ajuda.Obrigado!
Estou com o seguinte problema: Criei um método tendo como parâmetros um Texto contendo o código SQL a ser executado por um objeto TDBXCommand e outro parâmetro do tipo Variant onde passo um array com os valores dos parâmetros do SQL. O problema acontece é que passo o SQL (com os caracteres "?") com parâmetros e na hora de atribuir os valores o Objeto TDBXCommand não criou os respectivos parâmetros.
A seguir estão os códigos do Método e sua chamada:
//O Método:
function TAppDataBaseService.ExecuteSQLCommand(ASQLStm: String; args: Variant): Boolean;var FCommand: TDBXCommand; AResult: Boolean; i: Integer;begin AResult := False; if not GetSessionConnection.Connected then GetSessionConnection.Open;
try FCommand := GetSessionConnection.DBXConnection.CreateCommand;
FCommand.CommandType:=TDBXCommandTypes.DbxSQL;
FCommand.Text := ASQLStm;
FCommand.Prepare;
if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do FCommand.Parameters.Parameter[i].Value.AsVariant := args[i];
FCommand.ExecuteUpdate;
AResult := True; finally FreeAndNil(FCommand); Result := AResult; end;end;
//A Chamada:
DataBaseConnectionService.ExecuteSQLCommand ('INSERT INTO tb_teste(id, nome, idade, datanasc) VALUES ( ? , ? , ? , ? )', varArrayof([ID, Name, Idade, DataNasc]));
Não sei por que motivo o TDBXCommand (Objeto FCommand) não cria os parâmetros. Desde já agradeço a ajuda.Obrigado!
Pedro Neto
Curtidas 0
Respostas
Emerson Nascimento
17/06/2011
não conheço essa nova classe, mas creio que deva manter a forma de criação de parâmetros dos objetos tradicionais do DBX:
DataBaseConnectionService.ExecuteSQLCommand ('INSERT INTO tb_teste(id, nome, idade, datanasc) VALUES (:id, :nome, :idade, :datanasc)', varArrayof([ID, Name, Idade, DataNasc]));
DataBaseConnectionService.ExecuteSQLCommand ('INSERT INTO tb_teste(id, nome, idade, datanasc) VALUES (:id, :nome, :idade, :datanasc)', varArrayof([ID, Name, Idade, DataNasc]));
GOSTEI 0
Marco Salles
17/06/2011
Exemplo de uso do TDBXCommand
http://marcosalles.wordpress.com/2011/06/15/manipulando-metadados-criando-tabelas-campos-chaves-estrangeiras-utilizando-o-framework-dbxexpress-sem-dataset-delphi-2010-parte-iii/
Quanto ao InsertInto Troque o tipo do parâmetro args: Variant para args: oleVariant e
altere o codigo
claro que se precisar de outros tipo basta por exemplo booleanos se tem varBoolean etc...
ps) consultar o TVarType
http://marcosalles.wordpress.com/2011/06/15/manipulando-metadados-criando-tabelas-campos-chaves-estrangeiras-utilizando-o-framework-dbxexpress-sem-dataset-delphi-2010-parte-iii/
Quanto ao InsertInto Troque o tipo do parâmetro args: Variant para args: oleVariant e
altere o codigo
if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do case VarType(args[i])and VarTypeMask of varInteger:FCommand.Parameters.Parameter[i].Value.AsInt32 := args[i]; varOleStr,varString,varUString:FCommand.Parameters.Parameter[i].Value.AsString:=args[i]; varBoolean:FCommand.Parameters.Parameter[i].Value.AsBoolean :=args[i]; varDouble:FCommand.Parameters.Parameter[i].Value.AsDouble :=args[i]; varDate:FCommand.Parameters.Parameter[i].Value.AsDateTime :=args[i]; else raise Exception.Create('confira tipo'); end;
claro que se precisar de outros tipo basta por exemplo booleanos se tem varBoolean etc...
ps) consultar o TVarType
GOSTEI 0
Pedro Neto
17/06/2011
Prezado Marcos,
Obrigado pela resposta. Eu segui suas orientações, mas ainda não funcionou. Seria necessário chamar o método SetCount da propriedade Parameters do TDBXCommand primeiro, depois criar um objeto do tipo TDBXParameter, setar suas propriedades DataType e Value de acordo com o VarType de args[i] e por fim adicioná-lo (.Add) a Parameters?
Eu fiz isso conforme o código abaixo, porém ainda continua sem funcionar. Meu objetivo é deixar os códigos SQL prontos em um arquivo XML contendo as regras de negócio e seus parâmetros ("?"), e executá-los através deste método que seria genérico, onde a quantidade, valores e tipos do parâmetros seria definido de acordo com a características do SQL passado.
O método ficou assim, e a Chamada continua mesma, mas ainda continua sem funcionar, gerando um Access Violation:
function TAppDataBaseService.ExecuteSQLCommand(ASQLStm: String; args: OleVariant): Boolean;var FCommand: TDBXCommand; AResult: Boolean; i: Integer; VParam: TDBXParameter;
begin AResult := False; if not GetSessionConnection.Connected then GetSessionConnection.Open;
try FCommand := GetSessionConnection.DBXConnection.CreateCommand;
FCommand.CommandType := TDBXCommandTypes.DbxSQL;
FCommand.Text := ASQLStm;
FCommand.Parameters.SetCount((VarArrayHighBound(args, 1) + 1));
if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do begin
VParam := TDBXParameter.Create;
case VarType(args[i]) and VarTypeMask of varInteger: begin VParam.DataType := TDBXDataTypes.Int16Type; VParam.Value.AsInt32 := args[i]; end; varOleStr, varString, varUString: begin VParam.DataType := TDBXDataTypes.AnsiStringType; VParam.Value.AsString := args[i]; end; varBoolean: begin VParam.DataType := TDBXDataTypes.BooleanType; VParam.Value.AsBoolean = args[i]; end; varDouble: begin VParam.DataType := TDBXDataTypes.DoubleType; VParam.Value.AsDouble := args[i]; end; varDate: begin VParam.DataType := TDBXDataTypes.DateType; VParam.Value.AsDate := args[i]; end; varSmallint: begin VParam.DataType := TDBXDataTypes.Int16Type; VParam.Value.AsInt16[i]; end; varSingle: begin VParam.DataType := TDBXDataTypes.SingleType; VParam.Value.AsSingle := args[i]; end; varCurrency: begin VParam.DataType := TDBXDataTypes.CurrencyType; VParam.Value.AsCurrency := args[i]; end; varShortInt: begin VParam.DataType := TDBXDataTypes.Int8Type; VParam.Value.AsInt8 := args[i]; end; varWord: begin VParam.DataType := TDBXDataTypes.UInt16Type; VParam.Value.AsUInt16 := args[i]; end; varInt64: begin VParam.DataType := TDBXDataTypes.Int64Type; VParam.Value.AsInt64 := args[i]; end; else raise Exception.Create('Invalid Type'); end;
FCommand.Parameters.AddParameter(VParam);
end;
if not FCommand.IsPrepared then FCommand.Prepare;
FCommand.ExecuteUpdate;
AResult := True; finally FreeAndNil(FCommand); Result := AResult; end;end;
Obrigado pela resposta. Eu segui suas orientações, mas ainda não funcionou. Seria necessário chamar o método SetCount da propriedade Parameters do TDBXCommand primeiro, depois criar um objeto do tipo TDBXParameter, setar suas propriedades DataType e Value de acordo com o VarType de args[i] e por fim adicioná-lo (.Add) a Parameters?
Eu fiz isso conforme o código abaixo, porém ainda continua sem funcionar. Meu objetivo é deixar os códigos SQL prontos em um arquivo XML contendo as regras de negócio e seus parâmetros ("?"), e executá-los através deste método que seria genérico, onde a quantidade, valores e tipos do parâmetros seria definido de acordo com a características do SQL passado.
O método ficou assim, e a Chamada continua mesma, mas ainda continua sem funcionar, gerando um Access Violation:
function TAppDataBaseService.ExecuteSQLCommand(ASQLStm: String; args: OleVariant): Boolean;var FCommand: TDBXCommand; AResult: Boolean; i: Integer; VParam: TDBXParameter;
begin AResult := False; if not GetSessionConnection.Connected then GetSessionConnection.Open;
try FCommand := GetSessionConnection.DBXConnection.CreateCommand;
FCommand.CommandType := TDBXCommandTypes.DbxSQL;
FCommand.Text := ASQLStm;
FCommand.Parameters.SetCount((VarArrayHighBound(args, 1) + 1));
if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do begin
VParam := TDBXParameter.Create;
case VarType(args[i]) and VarTypeMask of varInteger: begin VParam.DataType := TDBXDataTypes.Int16Type; VParam.Value.AsInt32 := args[i]; end; varOleStr, varString, varUString: begin VParam.DataType := TDBXDataTypes.AnsiStringType; VParam.Value.AsString := args[i]; end; varBoolean: begin VParam.DataType := TDBXDataTypes.BooleanType; VParam.Value.AsBoolean = args[i]; end; varDouble: begin VParam.DataType := TDBXDataTypes.DoubleType; VParam.Value.AsDouble := args[i]; end; varDate: begin VParam.DataType := TDBXDataTypes.DateType; VParam.Value.AsDate := args[i]; end; varSmallint: begin VParam.DataType := TDBXDataTypes.Int16Type; VParam.Value.AsInt16[i]; end; varSingle: begin VParam.DataType := TDBXDataTypes.SingleType; VParam.Value.AsSingle := args[i]; end; varCurrency: begin VParam.DataType := TDBXDataTypes.CurrencyType; VParam.Value.AsCurrency := args[i]; end; varShortInt: begin VParam.DataType := TDBXDataTypes.Int8Type; VParam.Value.AsInt8 := args[i]; end; varWord: begin VParam.DataType := TDBXDataTypes.UInt16Type; VParam.Value.AsUInt16 := args[i]; end; varInt64: begin VParam.DataType := TDBXDataTypes.Int64Type; VParam.Value.AsInt64 := args[i]; end; else raise Exception.Create('Invalid Type'); end;
FCommand.Parameters.AddParameter(VParam);
end;
if not FCommand.IsPrepared then FCommand.Prepare;
FCommand.ExecuteUpdate;
AResult := True; finally FreeAndNil(FCommand); Result := AResult; end;end;
GOSTEI 0
Marco Salles
17/06/2011
Mas vc alterou o código , .. Mas enfim peguei o seu padrão e o alterei ficando assim
ps) testei aqui com um banco e esta funcionando bem
function Tform4.ExecuteSQLCommand(ASQLStm: String; args: oleVariant): Boolean; var FCommand: TDBXCommand; AResult: Boolean; i: Integer; VParam: TDBXParameter; begin AResult := False; if not GetSessionConnection.Connected then GetSessionConnection.Open; try FCommand := GetSessionConnection.DBXConnection.CreateCommand; FCommand.CommandType := TDBXCommandTypes.DbxSQL; FCommand.Text := ASQLStm; if not FCommand.IsPrepared then FCommand.Prepare; if not(VarIsNull(args)) and not(VarIsEmpty(args)) then for i := 0 to (VarArrayHighBound(args, 1)) do begin with FCommand.Parameters.Parameter[i].Value do case VarType(args[i]) and VarTypeMask of varInteger: begin AsInt32 := args[i]; end; varOleStr, varString, varUString: begin AsString := args[i]; end; varBoolean: begin AsBoolean := args[i]; end; varDouble: begin AsDouble := args[i]; end; varDate: begin AsDate := args[i]; end; varSmallint: begin AsInt16:=args[i]; end; varSingle: begin AsSingle := args[i]; end; varCurrency: begin AsCurrency := args[i]; end; varShortInt: begin AsInt8 := args[i]; end; varWord: begin AsUInt16 := args[i]; end; varInt64: begin AsInt64 := args[i]; end; else raise Exception.Create('Invalid Type'); end; end; FCommand.ExecuteUpdate; AResult := True; finally FreeAndNil(FCommand); Result := AResult; end; end;
ps) testei aqui com um banco e esta funcionando bem
GOSTEI 0
Pedro Neto
17/06/2011
Marcos,
Testei e não funcionou. Deu a mensagem "Invalid Ordinal". E o erro acontece no laço "for" quando a propriedade do Parameters.Parameter do TDBXCommand é acessada através do índice i. Estou acessando uma base de dados MS SQL 2008, e já testei um Código SQL sem parâmetros e funciona blz. Por que será que não funciona aqui hein? Tô quebrando a cabeça...
Testei e não funcionou. Deu a mensagem "Invalid Ordinal". E o erro acontece no laço "for" quando a propriedade do Parameters.Parameter do TDBXCommand é acessada através do índice i. Estou acessando uma base de dados MS SQL 2008, e já testei um Código SQL sem parâmetros e funciona blz. Por que será que não funciona aqui hein? Tô quebrando a cabeça...
GOSTEI 0
Marco Salles
17/06/2011
Eu utilizei o Firebird ...
Não tenho o MS SQL 2008 , porque o casamento do DataSnap com DbExpress e Firebird é perfeito
Teste ai com uma Base De DAdos Firebird
Talves com o MS SQL 2008 deve passar os perãmetros da forma tradicional com o emerson levantou no inicio do
THread.
Eu tb estou curuioso porque esta dand erro com Vc
Não tenho o MS SQL 2008 , porque o casamento do DataSnap com DbExpress e Firebird é perfeito
Teste ai com uma Base De DAdos Firebird
Talves com o MS SQL 2008 deve passar os perãmetros da forma tradicional com o emerson levantou no inicio do
THread.
Eu tb estou curuioso porque esta dand erro com Vc
GOSTEI 0
Pedro Neto
17/06/2011
Beleza Marcos, vou testar com o Firebird aqui e ver se funciona. O problema que estou notando é que os parâmetros deveriam ser criados na chamada do método Prepare, e não está acontecendo, pois checo a propriedade Count de Parameters e está = 0. Mas como falei, se passo um SQL sem parâmetros ("?") ele funciona legal. Obrigado mais uma vez e vou tentar aqui e te dar um retorno.
GOSTEI 0
Pedro Neto
17/06/2011
Marcos,
Realmente não consegui. Mesmo assim muito obrigado. Ainda não testei com outros SGBDs, só no MS SQL Server. Para resolver, criei um método que enxerta os valores no lugar dos caracteres marcadores dos parâmetros "?". Sei que não foi a melhor solução, pois o SQL enviado ao DB é otimizado a cada envio, ao contrário do código com os parâmetros.
Realmente não consegui. Mesmo assim muito obrigado. Ainda não testei com outros SGBDs, só no MS SQL Server. Para resolver, criei um método que enxerta os valores no lugar dos caracteres marcadores dos parâmetros "?". Sei que não foi a melhor solução, pois o SQL enviado ao DB é otimizado a cada envio, ao contrário do código com os parâmetros.
GOSTEI 0
Marco Salles
17/06/2011
Bem , eu consegui sem problema nenhum utilizando o firebird 2.1
Se quiser ver como eu fiz entre em contato por email que lhe envio o projeto . Delphixe
Se quiser ver como eu fiz entre em contato por email que lhe envio o projeto . Delphixe
GOSTEI 0