How to Get "_id" field value from kinvey.com - delphi

I been using kinvey.com, and every time I try to get Manga._id it returns null. Can you help me figure out why?
TManga = class
strict private
FSite,
FManga,
FID: String;
published
property Site : string read FSite write FSite;
property Manga : string read FManga write FManga;
property _id : string read FID write FID;
///////////////////////////////////////////////////////////////////////////
var
Mangas: TBackendObjectList<TManga>;
Manga : TManga;
QueryStr: TArray<string>;
i: Integer;
begin
with xQuery do
begin
Execute;
Mangas := TBackendObjectList<TManga>.Create;
QueryStr := TArray<string>.Create('');
xStorage.Storage.QueryObjects<TManga>('xxxx' ,QueryStr ,Mangas);
with xListBox do
begin
Items.BeginUpdate;
try
Items.Clear;
for I := 0 to Mangas.Count -1 do
begin
Manga := Mangas.Items[I];
items.add(Manga.Site + ' - ' + Manga._id) // Manga._id this is everytime null
end;
finally
Items.EndUpdate;
end;
end;
end;
http://i.hizliresim.com/M94QPN.png

Did you try using the value 'fields=_id' in one of the array elements of QueryStr?

Your column _id is always null because the Kinvey API doesn't get the _id column as a simple column but as the object ID of the record.
In order to get the object ID of your Manga record, you must to add a variable like this:
oEntity: TBackendEntityValue;
So right under this line in the "for" statement:
Manga := Mangas.Items[I];
You may add these two new lines:
oEntity := FBackendList.EntityValues[Manga]; // Gets the Kinvey object
Manga._id := oEntity.ObjectID; // Sets the _id property of the current TManga instance
One important thing you may take in mind is when you will add new records in your Kinvey collection. You don't have to write in the _id property of your new TManga item before you create your new record. However you will need to get it from Kinvey right after you insert the new record.
This code was adapted from the Embarcadero's ToDo sample:
procedure TDataModule1.AddBackendItem(const AItem: TManga);
var
oEntity: TBackendEntityValue;
begin
// After the execution of this command the new record will be inserted in Kinvey, and the variable oEntity will get the respective object ID
BackendStorage1.Storage.CreateObject<TManga>(
TMangaNames.BackendClassname, AItem, oEntity);
AItem._id := oEntity.ObjectID; // Updates the property _id of the current instance of TManga
FBackendList.Add(AItem, oEntity);
end;
I hope it can help you!

Related

ADOQuery Get Result (Delphi)

I Tried to get result from ADOQuery in Delphi. I wrote this function for Get a Name from table according custom ID.
function GetNameByID(Id : Integer) : string;
var query : string;
Begin
ShowMessage(GetDBGridViewIndex().ToString);
query := 'SELECT Name FROM Table1 WHERE ID=' + IntToStr(Id);
With ADOQuery do
Begin
try
SQL.Clear;
SQL.Add(query);
Open;
First;
Result:= // Need Get Result;
finally
Close;
end;
End;
ShowMessage(result);
End;
But I don't know how can return Result from ADOQuery.
TADOQuery is a descendant of TDataset.
You can iterate through the result records with the First, Next, Prior, and Last methods and find out if you've reached the end with Eof.
Within each result record you can access the fields with:
Fields[Index].AsString
Fields[Index].AsInteger
...
or
FieldByName(FieldName).AsString
FieldByName(FieldName).AsInteger
...
In this case you can access to the result using:
Result := Fields[0].AsString;
Result := FieldByName('Name').AsString;
After you Open the query, the cursor is pointing the First record. You don't need to call the First method after Open.

generate a number increases with a specific format ex 'PRT-00000'

I want to create auto numbering to my access database in delphi
example :
I have a database with part names , i want to create an auto id that counts number of these records and generates a name with number as this 'PRT-00000' and increase it with one each time i add a record and keeps this format of five digits , like this 'PRT-00001'
help me please and thanks a lot .
sorry for my poor english
Let's assume your Access table is named 'Parts' and has an AutoNumber
field named 'ID' and a Short Text field named 'PartNumber'. One way of generating the
PartNumber value would be to get Access to calculate it for you, but since you have asked about Delphi, I'm going to explain a way to do it in Delphi.
Please start a new, very simple project with just the following items on the main form:
A TAdoConnection configured to connect to your database;
A TAdoQuery configured to use the TAdoConnection with its SQL.Text property set
to 'select * from Parts'
A TDataSource and TDBGrid configured to display the contents of the TAdoQuery.
A TButton
Then, add the following code to the form's unit:
procedure TForm2.Button1Click(Sender: TObject);
begin
NewPart;
end;
procedure TForm2.NewPart;
const
sSelect = 'select * from Parts';
sPrefix = 'PRT-';
iDigits = 5;
var
PartNumber : String;
ID : Integer;
begin
qryParts.Insert;
try
// First, set the new record's PartNumber field to a temporary value
qryParts.FieldByName('PartNumber').AsString := 'xxxx';
// save the record so that we can then read the ID value Access has allocated to the record
qryParts.Post;
// read the ID value
ID := qryParts.FieldByName('ID').AsInteger;
// next, construct the desired value for the PartNumber field based on the ID
PartNumber := qryParts.FieldByName('ID').AsString;
// left-pad the PartNumber with zeroes
while Length(PartNumber) < iDigits do
PartNumber := '0' + PartNumber;
// pre-pend the PRT- prefix
PartNumber := sPrefix + PartNumber;
// put qryParts into its dsEdit state
qryParts.Edit;
qryParts.FieldByName('PartNumber').AsString := PartNumber;
finally
// post the record back to the Parts table
qryParts.Post;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
qryParts.Open;
end;
Update I've managed to get the new Part's autonumber ID in advance of the new Part being posted to the db. To use this, add the NewAutoNumber function and modify the NewPart method as shown below.
function TForm2.NewAutoNumber(ATable, AColumn: String): Integer;
var
vCat : OleVariant;
vTable : OleVariant;
vColumn : OleVariant;
begin
vCat := CreateOleObject('ADOX.Catalog');
vCat.ActiveConnection := AdoConnection1.ConnectionString;
vTable := vCat.Tables[ATable];
vColumn := vTable.Columns[AColumn];
Result := vColumn.Properties['Seed'].Value;
end;
procedure TForm2.NewPart;
const
sSelect = 'select * from Parts';
sPrefix = 'PRT-';
iDigits = 5;
var
PrvSql : String;
PartNumber : String;
ID : Integer;
begin
ID := NewAutoNumber('Parts', 'ID');
try
qryParts.Insert;
qryParts.FieldByName('PartNumber').AsString := 'xxxx';
qryParts.Post;
if not qryParts.Locate('ID', ID, []) then begin
raise exception.CreateFmt('Failed to create new Parts record with ID = %d', [ID]);
end;
PartNumber := qryParts.FieldByName('ID').AsString;
while Length(PartNumber) < iDigits do
PartNumber := '0' + PartNumber;
PartNumber := sPrefix + PartNumber;
qryParts.Edit;
qryParts.FieldByName('PartNumber').AsString := PartNumber;
finally
qryParts.Post;
end;
end;
Update #2 As an alternative to getting the ID value for a newly-added Parts record using
either of the methods above, it can be obtained by using the 'select ##identity' method. The simplest
way to do this is to add another TAdoQuery, qryAutoNumber to the form and to add this function to
get the AutoNumber value:
function TForm2.NewAutoNumberFromIdentity : Integer;
begin
if qryAutoNumber.Active then
qryAutoNumber.Close;
qryAutoNumber.SQL.Text := 'select ##identity';
qryAutoNumber.Open;
Result := qryAutoNumber.Fields[0].AsInteger;
end;
Note that to obtain the correct ID value, this function should be called immediately after calling qryParts.Post. However, I have included this
only for completeness but as far as I can see, it is largely pointless
because once the new Parts record has been posted, the ID AutoNumber value
can be read directly from the ID field of qryParts.

Data from ListBox to DataSet

I have DBGrid where I load names from DataSetPeople associated to table_people. I create a Drag and Drop procedure, where the user can drag a name and drop into a ListBox. The user can drop into a listbox_employees or listbox_manager.
MY PROBLEM
I want to create a relationship between people from table_people using the names that user drop in both listbox. I create table_relationship where employeeID match with managerID.
So, how can I get the name from each listbox, associate this name to an ID, and put this ID into a employeeID or managerID from DataSetRelationship associated to table_relationship ?
If your IDs are numeric (integer) values, you can use the TListBox.Items.Objects to store it when you fill it (in your drop event handler on the form):
var
PersonName: string;
PersonID: Integer;
begin
with YourDataModule do // Gives access to the tables in the data module
begin
PersonName := table_people.FieldByName('employeeName').AsString;
PersonID := table_people.FieldByName('employeeID').AsInteger);
end;
listbox_employees.Items.AddObject(PersonName, TObject(PersonID);
end;
For the manager, just change to the listbox for the manager and the field values for the manager.
To get the ID back out to use for an INSERT statement:
// Make sure both listboxes have the same number of items, of course.
var
EmployeeID: Integer;
ManagerID: Integer;
i: Integer;
begin
for i := 0 to ListBox_Employees.Items.Count - 1 do
begin
EmployeeID := Integer(ListBox_Employees.Items.Objects[i]);
ManagerID := Integer(ListBox_Manager.Items.Objects[i]);
if not YourDataModule.MakeRelationship(EmployeeID, ManagerID) then
ShowMessage('Unable to relate this employee and manager!');
end;
end;
// If you're using a SQL query, the `INSERT` should be created like this
// somewhere, like in your datamodule's OnCreate event
// qryRelationShips.SQL.Clear;
// qryRelationShips.SQL.Add('INSERT INTO table_relationship (employeeID, managerID)');
// qryRelationShips.SQL.Add('VALUES (:employeeID, :managerID)';
//
// Or you can type it into the SQL property in the Object Inspector at designtime
// INSERT INTO table_relationship (employeeID, managerID) VALUES (:employeeID, :managerID)
function TYourDataModule.MakeRelationship(const EmpID, MgrID: Integer): Boolean;
begin
Result := False;
// INSERT into your dataset:
qryRelationShips.ParamByName('employeeID').AsInteger := EmpID;
qryRelationShips.ParamByName('managerID').AsInteger := MgrID;
try
qryRelationShips.ExecSQL;
Result := qryRelationShips.RowsAffected;
finally
qryRelationShips.Close;
end;
end;
// If you're using a table instead of a query, getting a result is harder
function TYourDataModule.MakeRelationship(const EmpID, MgrID: Integer): Boolean;
begin
Result := True;
try
tblRelationShips.Insert;
tblRelationShips.FieldByName('employeeID').AsInteger := EmpID;
tblRelationShips.FieldByName('managerID').AsInteger := MgrID;
tblRelationShips.Post;
except
Result := False;
end;
end;
I hope you have made tables using SQLite database. So what you want to do is possible by using a query to insert the rows. Use db.execSQL();
You can keep a counter for incrementong the id values.

TStringList's addObject method

I want to know what this method call does:
stringList.addObject(String,Object);
I also want to know what this property does:
stringList.Objects[i]
It looks like key,value pair while adding. But while retrieving in a loop what gets retrieved?
I also see items[i] call.
I am confused with TStringList operations and TList operations.
It adds a pair of items: an entry in the TStringList.Strings list, and a matching TObject in the TStringList.Objects list.
This allows you to, for instance, store a list of strings that supply a name for the item, and an object that is the class containing the matching item.
type
TPerson=class
FFirstName, FLastName: string;
FDOB: TDateTime;
FID: Integer;
private
function GetDOBAsString: string;
function GetFullName: string;
published
property FirstName: string read FFirstName write FFirstName;
property LastName: string read FLastName write FLastName;
property DOB: TDateTime read FDOB write FDOB;
property DOBString: string read GetDOBAsString;
property FullName: string read GetFullName;
property ID: Integer read FID write FID;
end;
implementation
{TPerson}
function TPerson.GetDOBAsString: string;
begin
Result := 'Unknown';
if FDOB <> 0 then
Result := DateToStr(FDOB);
end;
function TPerson.GetFullName: string;
begin
Result := FFirstName + ' ' + FLastName; // Or FLastName + ', ' + FFirstName
end;
var
PersonList: TStringList;
Person: TPerson;
i: Integer;
begin
PersonList := TStringList.Create;
try
for i := 0 to 9 do
begin
Person := TPerson.Create;
Person.FirstName := 'John';
Person.LastName := Format('Smith-%d', [i]); // Obviously, 'Smith-1' isn't a common last name.
Person.DOB := Date() - RandRange(1500, 3000); // Make up a date of birth
Person.ID := i;
PersonList.AddObject(Person.LastName, Person);
end;
// Find 'Smith-06'
i := PersonList.IndexOf('Smith-06');
if i > -1 then
begin
Person := TPerson(PersonList[i]);
ShowMessage(Format('Full Name: %s, ID: %d, DOB: %s',
[Person.FullName, Person.ID, Person.DOBString]));
end;
finally
for i := 0 to PersonList.Count - 1 do
PersonList.Objects[i].Free;
PersonList.Free;
end;
This is clearly a contrived example, as it's not something you'd really find useful. It demonstrates the concept, though.
Another handy use is for storing an integer value along with a string (for instance, showing a list of items in a TComboBox or TListBox and a corresponding ID for use in a database query). In this case, you just have to typecast the integer (or anything else that is SizeOf(Pointer)) in the Objects array.
// Assuming LBox is a TListBox on a form:
while not QryItems.Eof do
begin
LBox.Items.AddObject(QryItem.Fields[0].AsString, TObject(QryItem.Fields[1[.AsInteger));
QryItems.Next;
end;
// User makes selection from LBox
i := LBox.ItemIndex;
if i > -1 then
begin
ID := Integer(LBox.Items.Objects[i]);
QryDetails.ParamByName('ItemID').AsInteger := ID;
// Open query and get info.
end;
In the case of storing things other than an actual TObject, you don't need to free the contents. Since they're not real objects, there's nothing to free except the TStringList itself.
The AddObject method lets you store a TObject address (pointer) associated to the string stored in the Item property. the Objects property is for access the stored objects.
Check this simple samplem that uses the AddObject to store an integer value associated to each string.
var
List : TStringList;
I : integer;
begin
try
List:=TStringList.Create;
try
List.AddObject('Item 1', TObject(332));
List.AddObject('Item 2', TObject(345));
List.AddObject('Item 3', TObject(644));
List.AddObject('Item 4', TObject(894));
for I := 0 to List.Count-1 do
Writeln(Format('The item %d contains the string "%s" and the integer value %d',[I, List[I], Integer(List.Objects[i])]));
finally
List.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
TStringList is more than a list of strings.
It can be used for name value pairs:
stringlist.Values['apple'] := 'one';
stringlist.Values['banana'] := 'two';
But it can also be used to associate strings with any object (or any pointer).
stringlist.AddObject('apple', TFruit.Create);
stringlist.AddObject('banana', TFruit.Create);
i := stringlist.IndexOf('apple');
if i >= 0 then
myfruit := stringlist.Objects[i] as TFruit;
TList is a list that stores pointers. They are not associated with strings.

Get an instance of a persistent object, given the identifier in string

In Delphi 7, how to get an instance of a persistent object, given the object identifier in string?
function TForm1.GetObject(Identifier: string): TPersistent;
begin
//what to do here?
end;
Example of use:
//If I have these declared...
public
MyString: string;
MyStringList: TStringList;
//the function will be used something like this
MyString:=TStringList(GetObject('MyStringList')).Text;
Thank you in advance and please apologize me for not being able to express my question clearly in English.
This is very common.
You need to hold a list of the object instances by name. You've already suggested this with your string list. This can be used to retrieve the instance by name. So:
When you create your object you do:
MyObjList := TStringList.Create;
MyObj := TMyObj.Create;
MyObjList.AddObject( 'Thing', MyObj );
MyObj2 := TMyObj.Create;
MyObjList.AddObject( 'Thing2', MyObj2 );
etc.
Now, to retrieve you simply do:
function GetObject( const AName : string ) : TMyObj;
begin
I := MyObjList.IndexOf( AName );
If I = -1 then
Raise Exception.Create( 'Cant find it' );
Result := MyObjList[I] as TMyObj;
end;
Bri
You could create a published property, which could be accessed via runtime type information (RTTI). See p.73 of Delphi in a nutshell and GetObjectProp.
Writeln((GetObjectProp(O,'ObjField') As TNamedObject).ObjectName);

Resources