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

17/06/2011

0

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

Responder

Posts

18/06/2011

Emerson Nascimento

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

Responder

18/06/2011

Marco Salles

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
Responder

19/06/2011

Pedro Neto

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;
Responder

19/06/2011

Marco Salles

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
Responder

19/06/2011

Pedro Neto

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...
Responder

19/06/2011

Marco Salles

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
Responder

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.
Responder

20/06/2011

Pedro Neto

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.
Responder

20/06/2011

Marco Salles

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
Responder

Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.

Aceitar