Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add a nested json object to the dataset #311

Open
Ravaut123 opened this issue Dec 10, 2019 · 3 comments
Open

add a nested json object to the dataset #311

Ravaut123 opened this issue Dec 10, 2019 · 3 comments

Comments

@Ravaut123
Copy link

I've change some code in TMVCJsonDataObjectsSerializer.JsonObjectToDataSet to have the values of a nested json object into the database. (see https://www.facebook.com/groups/delphimvcframework/permalink/2593069444109512/)

Is it possible to add the code into the repositorie?

procedure TMVCJsonDataObjectsSerializer.JsonObjectToDataSet(const AJsonObject: TJDOJsonObject; const ADataSet: TDataSet;
  const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
var
  Field: TField;

  sFieldName: string;
  sSubName: string;
  Name: string;

  SS: TStringStream;
  SM: TMemoryStream;
  NestedDataSet: TDataSet;


  procedure ParseFieldName(const aFieldName: string; out aTableName: String; out aColumnName: string);
  var
    i: Integer;
  begin
    i := Pos('.', aFieldName);
    if i > 1 then
    begin
      aTableName := Copy(aFieldName, 1, i - 1);
      aColumnName := Copy(aFieldName, i + 1);
    end
    else
    begin
      aColumnName := '';
      aTableName := aFieldName;
    end;
  end;

begin
  if (ADataSet.State in [dsInsert, dsEdit]) then
  begin
    for Field in ADataSet.Fields do
    begin
      name := GetNameAs(ADataSet.Owner, Field.Name, Field.FieldName);

      if (IsIgnoredAttribute(AIgnoredFields, name)) or (IsIgnoredComponent(ADataSet.Owner, Field.Name)) then
        continue;

      case GetNameCase(ADataSet, ANameCase) of
        ncLowerCase:
          name := LowerCase(Field.FieldName);
        ncUpperCase:
          name := UpperCase(Field.FieldName);
      end;

      sFieldName := Name;
      ParseFieldName(sFieldName, Name, sSubName);

      if not AJsonObject.Contains(name) then
        continue;

      if (AJsonObject[name].Typ = jdtObject) and (AJsonObject.Values[name].ObjectValue = nil) then
      // Nullable Type
      begin
        Field.Clear;
        continue;
      end;

      case Field.DataType of
        TFieldType.ftBoolean:
          Field.AsBoolean := AJsonObject.B[name];

        TFieldType.ftInteger, TFieldType.ftSmallint, TFieldType.ftShortint, TFieldType.ftByte, TFieldType.ftLongWord, TFieldType.ftWord, TFieldType.ftAutoInc:
          Field.AsInteger := AJsonObject.I[name];

        TFieldType.ftLargeint:
          Field.AsLargeInt := AJsonObject.L[name];

        TFieldType.ftCurrency:
          Field.AsCurrency := AJsonObject.F[name];

        TFieldType.ftSingle:
          Field.AsSingle := AJsonObject.F[name];

        TFieldType.ftFloat, TFieldType.ftFMTBcd, TFieldType.ftBCD:
          Field.AsFloat := AJsonObject.F[name];

        ftString, ftWideString, ftMemo, ftWideMemo:
        begin
          if (AJsonObject[name].Typ = jdtObject) then
          begin
            if sSubName.IsEmpty then
            begin
              Field.AsWideString := AJsonObject.O[name].ToJSON;
            end
            else
            begin
              begin
                Field.AsWideString := AJsonObject.O[name].S[sSubName];
              end;
            end;
          end
          else
          begin
            Field.AsWideString := AJsonObject.S[name];
          end;
        end;

        TFieldType.ftDate:
          Field.AsDateTime := ISODateToDate(AJsonObject.S[name]);

        TFieldType.ftDateTime:
          Field.AsDateTime := ISOTimeStampToDateTime(AJsonObject.S[name]);

        TFieldType.ftTimeStamp, TFieldType.ftTime:
          Field.AsDateTime := ISOTimeToTime(AJsonObject.S[name]);

{$IFDEF TOKYOORBETTER}
        TFieldType.ftGuid:
          Field.AsGuid := StringToGUID(AJsonObject.S[name]);
{$ENDIF}
        TFieldType.ftGraphic, TFieldType.ftBlob, TFieldType.ftStream:
          begin
            SS := TStringStream.Create(AJsonObject.S[name]);
            try
              SS.Position := 0;
              SM := TMemoryStream.Create;
              try
                TMVCSerializerHelper.DecodeStream(SS, SM);
                TBlobField(Field).LoadFromStream(SM);
              finally
                SM.Free;
              end;
            finally
              SS.Free;
            end;
          end;

        TFieldType.ftDataSet:
          begin
            NestedDataSet := TDataSetField(Field).NestedDataSet;

            NestedDataSet.First;
            while not NestedDataSet.Eof do
              NestedDataSet.Delete;

            case GetDataType(ADataSet.Owner, Field.Name, dtArray) of
              dtArray:
                begin
                  JsonArrayToDataSet(AJsonObject.A[name], NestedDataSet, AIgnoredFields, ANameCase);
                end;
              dtObject:
                begin
                  NestedDataSet.Edit;
                  JsonObjectToDataSet(AJsonObject.O[name], NestedDataSet, AIgnoredFields, ANameCase);
                  NestedDataSet.Post;
                end;
            end;
          end;
      else
        raise EMVCDeserializationException.CreateFmt('Cannot find type for field "%s"', [Field.FieldName]);
      end;
    end;
  end;
end;
@danieleteti
Copy link
Owner

Thanks for your contribute. However, we can merge this code only if the behaviour is simmetric with the serialization side. Can you provide an updated test project to show the serialization and the deserialization process?

@viniciussanchez
Copy link
Contributor

Hi, see more in https://github.com/viniciussanchez/dataset-serialize
It's perfect

@danieleteti
Copy link
Owner

@viniciussanchez the project uses system.json which is quite slow compared to jsondataobjects (used by dmvcframework). Having a subproject for dataset serialization is ok (if adds something to the current implementation), but it should be simple to integrate and must use jsondataobjects. Thank you for suggesting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants