Problemas na criação dos Parâmetros de um Objeto TDBxCommand
17/06/2011
0
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
Posts
18/06/2011
Emerson Nascimento
DataBaseConnectionService.ExecuteSQLCommand ('INSERT INTO tb_teste(id, nome, idade, datanasc) VALUES (:id, :nome, :idade, :datanasc)', varArrayof([ID, Name, Idade, DataNasc]));
18/06/2011
Marco Salles
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
19/06/2011
Pedro Neto
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;
19/06/2011
Marco Salles
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
19/06/2011
Pedro Neto
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...
19/06/2011
Marco Salles
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
19/06/2011
Pedro Neto
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.
20/06/2011
Pedro Neto
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.
20/06/2011
Marco Salles
Se quiser ver como eu fiz entre em contato por email que lhe envio o projeto . Delphixe
Clique aqui para fazer login e interagir na Comunidade :)