Ver Mensaje Individual
  #8  
Antiguo 17-02-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Reputación: 29
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por roman Ver Mensaje
¿Para qué si no, están esos métodos SetAsXYZ? Ya sea en TParam o TField...
En TField están para asignar fácilmente un valor al campo, aunque dicho valor esté expresado bajo otro tipo de dato, realizando una conversión implícita del valor asignado. Mientras que en TParam tal conversión no es llevada a cabo. En este caso es el objeto TParam el que se "convierte", no el valor dado.

El extrañamiento viene de la sorpresa de esta "inesperada" diferencia de comportamiento en propiedades que, pareciera, "deberían" hacer lo mismo.

Quizá sólo es cosa de costumbre y el que se pierde la convicción de que habría un "StrToFloat" implícito al usar AsString con un parámetro definido como numérico flotante.

Pensando en voz alta, en TField la propiedad DataType está muy relacionada con la clase del objeto y la manera en que guarda el dato, como quien dice la clase es su determinante. En TParam el valor es un Variant (no hay clases específicas derivadas de TParam), y quizá esta es la piedra angular que explica la diferencia. Al guardar TParam el valor en un Variant resulta tentador (y esperable) que ese Variant pueda ser, tal cual, lo que le sea asignado, creándose entonces la obligación de ajustar DataType al tipo del variante interno y no al revés.

¡Pero no! Pasé por alto algo importante en el código que pegué antes. SetAsVariant no cambia DataType a menos que éste se encuentre indefinido (ftUnknown):
Código Delphi [-]
procedure TParam.SetAsVariant(const Value: Variant);
begin
  if ParamRef = Self then
  begin
    FBound := not VarIsClear(Value);
    FNull := VarIsClear(Value) or VarIsNull(Value);
    if FDataType = ftUnknown then
      case VarType(Value) of
        varSmallint, varShortInt, varByte: FDataType := ftSmallInt;
        varWord, varInteger: FDataType := ftInteger;
        varCurrency: FDataType := ftBCD;
        varLongWord, varSingle, varDouble: FDataType := ftFloat;
        varDate: FDataType := ftDateTime;
        varBoolean: FDataType := ftBoolean;
        varString, varOleStr: if FDataType <> ftFixedChar then FDataType := ftString;
        varInt64: FDataType := ftLargeInt;
      else
        if VarType(Value) = varSQLTimeStamp then
          FDataType := ftTimeStamp
        else if VarType(Value) = varFMTBcd then
          FDataType := ftFMTBcd
        else 
          FDataType := ftUnknown;
      end;
    FData := Value;
  end else
    ParamRef.SetAsVariant(Value);
end;

A ver. Entonces si asignamos con la propiedad Value, el DataType que hayamos definido en tiempo de diseño se mantiene, lo cual es frecuentemente deseable. Mientras que las propiedades AsXXX nos servirán para hacer asignación de valor y cambio de tipo con una sola instrucción.

Creo que ahora tiene más lógica. Cuando se quiera o se necesite conservar el tipo definido en tiempo de diseño debe usarse Value. Cuando se quiera o necesite ajustar el tipo (o no importe si éste cambia) puede usarse AsXXX.

Sólo tener en cuenta que en determinadas ocasiones, debido a lo anteriormente visto, podría ser obligado escribir algo como
Código Delphi [-]
Parametro.Value := StrToXXX (Edit1.Text);
en lugar de
Código Delphi [-]
Parametro.AsString := Edit1.Text;

EDITO:

No sé por qué me queda la sensación de que hay un cabo suelto en todo esto, quizá es el desconocimiento de cómo son transferidos los parámetros al servidor...

¡Es más! Creo que uno no debería usar las propiedades AsXXX de TParam con el mero propósito de "facilitar cualquier asignación". Más bien con el bien intencionado propósito de asignar un valor y buscar que el DataType cambie a / se mantenga en el tipo específico de dicho valor, porque, para el contexto de la consulta SQL, ese tipo específico es el que se necesita.

Tomando texto de la ayuda e interpretándolo:

Cita:
Set AsFloat to assign the value for a float field to the parameter. Setting AsFloat sets the DataType property to ftFloat.
Establezca AsFloat para asignar el valor al parámetro para corresponder a un campo flotante...

Cita:
Use Value in generic code that manipulates the values of parameters without needing to know the field type the parameters represent.
Utilice Value en código genérico ["en general"] que manipule el valor de los parámetros sin necesidad de conocer el tipo de campo que éstos representan.

El "cabo suelto" era por esta sensación de que podría usarse AsXXX indiscriminadamente, para "facilitar cualquier asignación". Está bien que se usen esas propiedades para facilitar asignaciones, pero no cuando eso cause que el tipo del parámetro cambie a uno que no corresponda al contexto de la sentencia SQL, AUN cuando la sentencia funcione con la versión del motor de base de datos en turno. No sería del todo confiable, pues se supone que el DataType y el valor en sí del parámetro son los que determinan el valor que es enviado al servidor. No es lo mismo que le llegue un 5 que un '5', cualquiera que sea el formato interno del envío.

Creo que convendría investigar la forma en que el DataType influye en lo que es enviado al servidor y por qué en algunos casos, como el expuesto por Carlos, no hay falla.

Última edición por Al González fecha: 17-02-2009 a las 09:17:49.
Responder Con Cita