Continuing on the previous LINQ post, I’ll just show a couple of more features possible using kbmMW’s Linq.
Returning an object or a list of objects as result
Remember in LINQ #1 where I showed how to work with classes and objects using kbmMW Linq? We already defined the following object. If you dont remember please read previous LINQ #1 blog post.
[kbmMW_Linq] TMyData = class private FName:string; FAddress:string; FAge:integer; public constructor Create(const AName:string; const AAddress:string; const AAge:integer); property Name:string read FName write FName; property Address:string read FAddress write FAddress; property Age:integer read FAge write FAge; end;
Again I add a number of instances to an object list, so we have something to work with.
But this time I will show how to get a TMyData instance back from kbmMW Linq alternatively how to get a list of matching TMyData back.
procedure TForm1.TestObjecs; var lst,lst2:TObjectList<TMyData>; md:TMyData; i:integer; begin lst:=TObjectList<TMyData>.Create; try lst.Add(TMyData.Create('Kim','Address 1',49)); lst.Add(TMyData.Create('Hans','Address 2',22)); lst.Add(TMyData.Create('Jens','Address 3',33)); lst.Add(TMyData.Create('Joe','Address 3',77)); lst.Add(TMyData.Create('John','Address 4',33)); md:=Linq.Using(lst).Where('Age=77').AsGeneric.&Object<TMyData>; try if md<>nil then Memo1.Lines.Add('Age=77 match '+md.Name) else Memo1.Lines.Add('No match for Age=77'); finally md.Free; end; lst2:=Linq.Using(lst).Where('Age=33').AsGeneric.List<TMyData>; try if lst2<>nil then begin for md in lst2 do Memo1.Lines.Add('Age=33 match '+md.Name); end else Memo1.Lines.Add('No match for Age=33'); finally lst2.Free; end; finally lst.Free; end; end;
The returned objects are not references to existing objects, but are generated by the Linq framework, so you must remember to free them when they are no longer of interest.
If nothing match, nil will be returned.
This sample shows how to return object of the same type as the ones originally being in the Using clause. However you can use any class (registered with kbmMW) as a result. Only fields/properties that has matching names will be filled.
So having an object like this:
type [kbmMW_Linq] TMyData2 = class private FID:string; FName:string; FAddress:string; FZipCode:string; public property ID:string read FID write FID; property Name:string read FName write FName; property Address:string read FAddress write FAddress; property ZipCode:string read FZipCode write FZipCode; end;
Remember to register the TMyData2 class along with the previously registered TMyData class:
TkbmMWRTTI.EnableRTTI([TMyData,TObjectList<TMyData>,TMyData2]); kbmMWRegisterKnownClasses([TMyData,TObjectList<TMyData>,TMyData2]);
While remembering that lst is still an instance of TObjectList<TMyData>, it’s perfectly legal to do:
var md2:TMyData2; ... md2:=Linq.Using(lst).Where('Age=77').AsGeneric.&Object<TMyData2>;
You will be returned a TMyData2 object instance where only the Name and Address properties has values.
The same method can be applied to JSON, BSON, Messagepack, YAML and XML data too, which makes it a very easy thing to convert parts of structured documents to objects and object lists.