varios update una tabla registros registro modificar eliminar datos comando campo borrar actualizar delphi delphi-7 rtti

delphi - update - ¿Hay alguna manera de actualizar un campo en un registro sabiendo el nombre y el valor del campo?



modificar registro sql server (2)

Lo que sabe Delphi 7 RTTI, y se puede recuperar de TypeInfo(aRecordType) , es:

  • El nombre del tipo de registro;
  • El tamaño global récord;
  • El desplazamiento y el tipo de cada variable contada de referencia dentro del registro (cadena / variante / cadena más amplia / matriz dinámica / otro registro anidado que contiene variables contadas de referencia).

La información más reciente es necesaria para liberar la memoria utilizada por cada variable de referencia dentro del registro, o copiar el contenido del registro, en tiempo de ejecución. La inicialización del registro también se realiza en el código generado por el compilador (si el registro se crea en la pila), ya sea a través del método _InitializeRecord() , con un relleno global a 0 cuando se instancia una clase o una matriz dinámica.

Es igual para los tipos de record y de object , en todas las versiones de Delphi.

Puede observar que hay un error en la versión moderna de Delphi (incluyendo Delphi 2009 y 2010 al menos), que a veces no crea el código para inicializar objetos en la pila. Tendrá que usar el registro en su lugar, pero romperá la compatibilidad con la versión anterior de Delphi. :(

Aquí está la estructura utilizada para almacenar estos datos RTTI:

type TFieldInfo = packed record TypeInfo: ^PDynArrayTypeInfo; // information of the reference-counted type Offset: Cardinal; // offset of the reference-counted type in the record end; TFieldTable = packed record Kind: byte; Name: string[0]; // you should use Name[0] to retrieve offset of Size field Size: cardinal; // global size of the record = sizeof(aRecord) Count: integer; // number of reference-counted field info Fields: array[0..0] of TFieldInfo; // array of reference-counted field info end; PFieldTable = ^TFieldTable;

Usando estos datos, aquí está, por ejemplo, lo que puede hacer:

Por ejemplo, aquí es cómo se pueden comparar dos registros del mismo tipo, utilizando este RTTI:

/// check equality of two records by content // - will handle packed records, with binaries (byte, word, integer...) and // string types properties // - will use binary-level comparison: it could fail to match two floating-point // values because of rounding issues (Currency won''t have this problem) function RecordEquals(const RecA, RecB; TypeInfo: pointer): boolean; var FieldTable: PFieldTable absolute TypeInfo; F: integer; Field: ^TFieldInfo; Diff: cardinal; A, B: PAnsiChar; begin A := @RecA; B := @RecB; if A=B then begin // both nil or same pointer result := true; exit; end; result := false; if FieldTable^.Kind<>tkRecord then exit; // raise Exception.CreateFmt(''%s is not a record'',[Typ^.Name]); inc(PtrUInt(FieldTable),ord(FieldTable^.Name[0])); Field := @FieldTable^.Fields[0]; Diff := 0; for F := 1 to FieldTable^.Count do begin Diff := Field^.Offset-Diff; if Diff<>0 then begin if not CompareMem(A,B,Diff) then exit; // binary block not equal inc(A,Diff); inc(B,Diff); end; case Field^.TypeInfo^^.Kind of tkLString: if PAnsiString(A)^<>PAnsiString(B)^ then exit; tkWString: if PWideString(A)^<>PWideString(B)^ then exit; {$ifdef UNICODE} tkUString: if PUnicodeString(A)^<>PUnicodeString(B)^ then exit; {$endif} else exit; // kind of field not handled end; Diff := sizeof(PtrUInt); // size of tkLString+tkWString+tkUString in record inc(A,Diff); inc(B,Diff); inc(Diff,Field^.Offset); inc(Field); end; if CompareMem(A,B,FieldTable.Size-Diff) then result := true; end;

Por lo tanto, para su propósito, lo que Delphi 7 RTTI podría hacerle saber en tiempo de ejecución, es la posición de cada cadena dentro de un registro. Usando el código anterior, puede crear fácilmente una función usando el índice de campo:

procedure UpdateStringField(StringFieldIndex: integer; const FieldValue: string);

Pero simplemente no tiene la información necesaria para implementar su solicitud:

  • Los nombres de los campos no se almacenan dentro del RTTI (solo el nombre del tipo de registro global, e incluso no siempre AFAIK);
  • Solo los campos contados de referencia tienen un desplazamiento, no otros campos de tipo simple (como entero / doble ...).

Si realmente necesita esta función, la única solución bajo Delphi 7 es usar no registros, sino clases.

En Delphi 7, si creas una clase con campos publicados, tendrás toda la información necesaria para todos los campos publicados. A continuación, puede actualizar dicho contenido de campo publicado. Esto es lo que hace el tiempo de ejecución de VCL al deserializar el contenido .dfm en instancias de clase o con un enfoque de ORM .

Dado un registro:

MyRecord = record Company: string; Address: string; NumberOfEmplyees: integer;

puedes escribir una llamada de función como

function UpdateField(var FieldName: string; FieldValue: variant): bool;

así que eso:

UpdateField(''Company'', ''ABC Co'');

actualizaría MyRecord.Company a ''ABC Co''?

Busqué un ejemplo pero todo lo que encontré es para una base de datos. Cualquier ayuda que me señale en la dirección correcta es apreciada.

Gracias carlos


Necesita las versiones modernas de Delphi para hacer lo que pide sin tener que recurrir a la codificación manual de las búsquedas, por ejemplo, a través de una tabla.

El RTTI actualizado introducido en Delphi 2010 puede admitir lo que está buscando, pero no hay nada en Delphi 7 que haga esto por los registros.