Problemas na criação dos Parâmetros de um Objeto TDBxCommand

Delphi

17/06/2011

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!
Pedro Neto

Pedro Neto

Curtidas 0

Respostas

Emerson Nascimento

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]));

GOSTEI 0
Marco Salles

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

    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

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;
GOSTEI 0
Marco Salles

Marco Salles

17/06/2011

Mas vc alterou o código , .. Mas enfim peguei o seu padrão e o alterei ficando assim

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

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...
GOSTEI 0
Marco Salles

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
GOSTEI 0
Pedro Neto

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

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.
GOSTEI 0
Marco Salles

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
GOSTEI 0
POSTAR