使用 TypInfo 例程设置 属性 值

Set property value with TypInfo routine

通过以下方法将数据集字段值分配给属性:

var
  lvRuntimeContext: TRttiContext;
  lvRuntimeType: TRttiType;
  lvProp: TRttiProperty;
  lvAttr: TCustomAttribute;
  lvCol: EntityColumnAttrib;
begin

  if DataAccess.DataSet.Active then
  begin
    lvRuntimeContext := TRttiContext.Create;

    try
      lvRuntimeType := lvRuntimeContext.GetType(EntityColumnClassType);

      for lvProp in lvRuntimeType.GetProperties do
        for lvAttr in lvProp.GetAttributes do
          if lvAttr is EntityColumnAttrib then
          begin
            lvCol := (lvAttr as EntityColumnAttrib);

            if lvCol.InCurrentTable then
              case lvCol.FieldType of
                ftBytes: begin

                end;

                ftDateTime: lvProp.SetValue(ASystemColumns, TValue.From<TDateTime>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsDateTime));
              else
                lvProp.SetValue(ASystemColumns, TValue.From<Variant>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsVariant));
              end;

          end;
    finally
      lvRuntimeContext.Free;
    end;
  end;

在我的一个 类 中有一个 属性 类型 TMemoryStream 我想从 DataSet 字段赋值(SQL服务器: binary type) to it, 我该如何用这个方法做到这一点?

您可以使用 DataSet 的 CreateBlobStream() 方法为所需的 TField 获取只读 TStream,用它做任何您需要的事情,然后在完成后释放它。

如果可能,您应该更改 属性 以接受任何一般性 TStream,而不仅仅是具体 TMemoryStream。这样,您可以通过 RTTI 将 blob TStream 按原样直接分配给您的 属性(TValue 可以从任何 TObject 指针隐式创建):

var
  lvRuntimeContext: TRttiContext;
  lvRuntimeType: TRttiType;
  lvProp: TRttiProperty;
  lvAttr: TCustomAttribute;
  lvCol: EntityColumnAttrib;
  lStrm: TStream;
begin    
  if DataAccess.DataSet.Active then
  begin
    lvRuntimeContext := TRttiContext.Create;
    try
      lvRuntimeType := lvRuntimeContext.GetType(EntityColumnClassType);

      for lvProp in lvRuntimeType.GetProperties do
      begin
        for lvAttr in lvProp.GetAttributes do
        begin
          if lvAttr is EntityColumnAttrib then
          begin
            lvCol := (lvAttr as EntityColumnAttrib);

            if lvCol.InCurrentTable then
            begin
              case lvCol.FieldType of
                ftBytes: begin
                  lStrm := DataAccess.DataSet.CreateBlobStream(DataAccess.DataSet.FieldByName(lvCol.FieldName), bmRead);
                  try
                    lvProp.SetValue(ASystemColumns, lStrm);
                  finally
                    lStrm.Free;
                  end;
                end;

                ftDateTime: begin
                  lvProp.SetValue(ASystemColumns, TValue.From<TDateTime>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsDateTime));
                end;
              else
                lvProp.SetValue(ASystemColumns, TValue.From<Variant>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsVariant));
              end;
            end;
          end;
        end;
      end;
    finally
      lvRuntimeContext.Free;
    end;
  end;
end;

如果属性必须继续使用TMemoryStream,那么您将不得不创建一个临时TMemoryStream对象,将blob数据复制到其中(您可以使用TStream.CopyFrom() ),然后将其分配给 属性:

var
  lvRuntimeContext: TRttiContext;
  lvRuntimeType: TRttiType;
  lvProp: TRttiProperty;
  lvAttr: TCustomAttribute;
  lvCol: EntityColumnAttrib;
  lBlobStrm: TStream;
  lMemStrm: TMemoryStream;
begin    
  if DataAccess.DataSet.Active then
  begin
    lvRuntimeContext := TRttiContext.Create;
    try
      lvRuntimeType := lvRuntimeContext.GetType(EntityColumnClassType);

      for lvProp in lvRuntimeType.GetProperties do
      begin
        for lvAttr in lvProp.GetAttributes do
        begin
          if lvAttr is EntityColumnAttrib then
          begin
            lvCol := (lvAttr as EntityColumnAttrib);

            if lvCol.InCurrentTable then
            begin
              case lvCol.FieldType of
                ftBytes: begin
                  lMemStrm := TMemoryStream.Create;
                  try
                    lBlobStrm := DataAccess.DataSet.CreateBlobStream(DataAccess.DataSet.FieldByName(lvCol.FieldName), bmRead);
                    try
                      lMemStrm.CopyFrom(lBlobStrm, 0);
                    finally
                      lBlobStrm.Free;
                    end;
                    lMemStrm.Position := 0;
                    lvProp.SetValue(ASystemColumns, lMemStrm);
                  finally
                    lMemStrm.Free;
                  end;
                end;

                ftDateTime: begin
                  lvProp.SetValue(ASystemColumns, TValue.From<TDateTime>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsDateTime));
                end;
              else
                lvProp.SetValue(ASystemColumns, TValue.From<Variant>(DataAccess.DataSet.FieldByName(lvCol.FieldName).AsVariant));
              end;
            end;
          end;
        end;
      end;
    finally
      lvRuntimeContext.Free;
    end;
  end;
end;