I'm trying to update and delete my record.
I'm using dbgrid as to show the database and i use uniquery to do the query.
I managed to do the insert query but not with the update and delete.
Here is my code :
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids, Vcl.DBGrids, Data.DB,
DBAccess, Uni, UniProvider, MySQLUniProvider, MemDS, Vcl.StdCtrls, DAScript,
UniScript;
type
TForm1 = class(TForm)
UniConnection1: TUniConnection;
MySQLUniProvider1: TMySQLUniProvider;
UniDataSource1: TUniDataSource;
Button1: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Label1: TLabel;
Edit1: TEdit;
Label2: TLabel;
Label3: TLabel;
Edit2: TEdit;
Edit3: TEdit;
Label4: TLabel;
DBGrid1: TDBGrid;
UniQuery1: TUniQuery;
UniScript1: TUniScript;
procedure Button1Click(Sender: TObject);
procedure DBGrid1CellClick(Column: TColumn);
procedure Button5Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Application.Terminate();
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
UniQuery1.Edit;
UniQuery1.SQL.Add('UPDATE barang SET id:=i, name:=nam, stock:=st where id=:i');
UniQuery1.ParamByName('i').AsString := Edit1.Text;
UniQuery1.ParamByName('nam').AsString := Edit2.Text;
UniQuery1.ParamByName('st').AsString := Edit3.Text;
UniQuery1.ExecSQL;
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
UniQuery1.Insert;
UniQuery1.FieldByName('ID').AsString := Edit1.Text;
UniQuery1.FieldByName('Name').AsString := Edit2.Text;
UniQuery1.FieldByName('Stock').AsString := Edit3.Text;
UniQuery1.Post;
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
UniQuery1.Edit;
UniQuery1.SQLdelete('DELETE FROM barang where id=:i');
UniQuery1.ParamByName('i').AsString:=edit1.Text;
UniQuery1.ExecSQL;
end;
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
edit1.Text := DBGrid1.Fields[0].asstring;
edit2.text := DBGrid1.Fields[1].asstring;
edit3.Text := DBGrid1.Fields[2].asstring;
end;
end.
Thanks!
You're using the wrong syntax for your query.
The query does not use Delphi syntax and := does not make sense in that context.
Change the query to:
UniQuery1.SQL.Add('UPDATE barang SET id= :i, name= :nam, stock = :st where id= :i');
The : is a prefix that tells TQuery that these are named parameters.
Furthermore it makes little sense to set id = :i where id = :i that's a no-op.
So you can simplify the query to:
UniQuery1.SQL.Add('UPDATE barang SET name= :nam, stock = :st where id= :i');
In addition you don't have to insert/edit the queries.
These methods do not do what you think they do.
The insertion and editing is already being done by your SQL statements.
Don't use SQL.Add. It's slow and error prone, because if there is already text in your SQL the added text will clash with the SQL that's already there.
Never use SQL.Add ever again.
Change the first method like so:
procedure TForm1.Button4Click(Sender: TObject);
begin
UniQuery1.SQL.Text:= 'UPDATE barang SET name= :nam, stock = :st where id=:i';
UniQuery1.ParamByName('i').AsString := Edit1.Text;
UniQuery1.ParamByName('nam').AsString := Edit2.Text;
UniQuery1.ParamByName('st').AsString := Edit3.Text;
UniQuery1.ExecSQL;
end;
This method does not make any sense.
procedure TForm1.Button5Click(Sender: TObject);
begin
UniQuery1.Insert; //insert what? A query is not a table.
UniQuery1.FieldByName('ID').AsString := Edit1.Text;
UniQuery1.FieldByName('Name').AsString := Edit2.Text;
UniQuery1.FieldByName('Stock').AsString := Edit3.Text;
UniQuery1.Post; //makes no sense here.
end;
Just replace this with a INSERT INTO.... sql statement.
Finally the last method should look like:
procedure TForm1.Button6Click(Sender: TObject);
begin
UniQuery1.SQL.Text:= 'DELETE FROM barang where id=:i';
UniQuery1.ParamByName('i').AsString:=edit1.Text;
UniQuery1.ExecSQL;
end;
Surely you've figured out the there is no method called SQLdelete?
You need to rethink the concept.
It's the SQL statement that does the work.
The Query only cares if the statement is a select -> if so so Query.Open.
Or if it will change the data (delete/insert/update) -> so Query.ExecSQL.
All the rest is done in the SQL.Text.
Query.Edit etc
Yes you can do Query.Edit.
This puts the dataset in edit mode and allows the user to change fields in the query. The database layer will then transmit these changes to the underlying database tables.
However this only works if the query is simple. If not it will silently break and not update your tables.
Only use edit/insert/delete/post/cancel etc with Tables.
Related
What happened to the JSON deserializer of Delphi Sydney (10.4.1)?
After the migration from Delphi Seattle to Sydney, the standard marshal has problems with the deserialization of simple records.
Here is an example and simplified representation of my problem:
Data structure - Interation 1:
TAnalysisAdditionalData=record {order important for marshaling}
ExampleData0:Real; {00}
ExampleData1:Real; {01}
ExampleData2:String; {02}
end;
JSON representation:
"AnalysisAdditionalData":[0,1,"ExampleString"]
Data structure - Interation x, 5 years later:
TAnalysisAdditionalData=record {order important for marshaling}
ExampleData0:Real; {00}
ExampleData1:Real; {01}
ExampleData2:String; {02}
ExampleData3:String; {03} {since version 2016-01-01}
ExampleData4:String; {04} {since version 2018-01-01}
ExampleData5:String; {05}
end;
JSON representation:
"AnalysisAdditionalData":[0,1,"ExampleString0","ExampleString1","ExampleString2","ExampleString3"]
After interation 1, three string fields have been added.
If I now confront the standard marshal of Delphi Sydney (no custom converter, reverter, etc.) with an old dataset, so concretely with the data "AnalysisAdditionalData":[0,1, "ExampleString"], Sydney throws an EArgumentOutOfBoundsException because the 3 strings are expected - the deserialization fails.
Exit point is in Data.DBXJSONReflect in method TJSONUnMarshal.JSONToTValue - location marked below:
function TJSONUnMarshal.JSONToTValue(JsonValue: TJSONValue;
rttiType: TRttiType): TValue;
var
tvArray: array of TValue;
Value: string;
I: Integer;
elementType: TRttiType;
Data: TValue;
recField: TRTTIField;
attrRev: TJSONInterceptor;
jsonFieldVal: TJSONValue;
ClassType: TClass;
Instance: Pointer;
begin
// null or nil returns empty
if (JsonValue = nil) or (JsonValue is TJSONNull) then
Exit(TValue.Empty);
// for each JSON value type
if JsonValue is TJSONNumber then
// get data "as is"
Value := TJSONNumber(JsonValue).ToString
else if JsonValue is TJSONString then
Value := TJSONString(JsonValue).Value
else if JsonValue is TJSONTrue then
Exit(True)
else if JsonValue is TJSONFalse then
Exit(False)
else if JsonValue is TJSONObject then
// object...
Exit(CreateObject(TJSONObject(JsonValue)))
else
begin
case rttiType.TypeKind of
TTypeKind.tkDynArray, TTypeKind.tkArray:
begin
// array
SetLength(tvArray, TJSONArray(JsonValue).Count);
if rttiType is TRttiArrayType then
elementType := TRttiArrayType(rttiType).elementType
else
elementType := TRttiDynamicArrayType(rttiType).elementType;
for I := 0 to Length(tvArray) - 1 do
tvArray[I] := JSONToTValue(TJSONArray(JsonValue).Items[I],
elementType);
Exit(TValue.FromArray(rttiType.Handle, tvArray));
end;
TTypeKind.tkRecord, TTypeKind.tkMRecord:
begin
TValue.Make(nil, rttiType.Handle, Data);
// match the fields with the array elements
I := 0;
for recField in rttiType.GetFields do
begin
Instance := Data.GetReferenceToRawData;
jsonFieldVal := TJSONArray(JsonValue).Items[I]; <<<--- Exception here (EArgumentOutOfBoundsException)
// check for type reverter
ClassType := nil;
if recField.FieldType.IsInstance then
ClassType := recField.FieldType.AsInstance.MetaclassType;
if (ClassType <> nil) then
begin
if HasReverter(ClassType, FIELD_ANY) then
RevertType(recField, Instance,
Reverter(ClassType, FIELD_ANY),
jsonFieldVal)
else
begin
attrRev := FieldTypeReverter(recField.FieldType);
if attrRev = nil then
attrRev := FieldReverter(recField);
if attrRev <> nil then
try
RevertType(recField, Instance, attrRev, jsonFieldVal)
finally
attrRev.Free
end
else
recField.SetValue(Instance, JSONToTValue(jsonFieldVal,
recField.FieldType));
end
end
else
recField.SetValue(Instance, JSONToTValue(jsonFieldVal,
recField.FieldType));
Inc(I);
end;
Exit(Data);
end;
end;
end;
// transform value string into TValue based on type info
Exit(StringToTValue(Value, rttiType.Handle));
end;
Of course, this may make sense for people who, for example, only work with Sydney, or at least with Delphi versions above Seattle, or have started with these versions. I, on the other hand, have only recently been able to make the transition from Seattle to Sydney (Update 1).
Delphi Seattle has no problems with the missing record fields. Why should it, when they can be left untouched as default? Absurdly, however, Sydney has no problems with excess data.
Is this a known Delphi Sydney bug? Can we expect a fix? Or can the problem be worked around in some other way, i.e. compiler directive, Data.DBXJSONReflect.TCustomAttribute, etc.? Or, is it possible to write a converter/reverter for records? If so, is there a useful guide or resource that explains how to do this?
I, for my part, have unfortunately not found any useful information in this regard, only many very poorly documented class descriptions.
Addendum: Yes, it looks like it is a Delphi bug, and in my opinion a very dangerous one. Luckily, and I'm just about to deploy a major release, I discovered the bug while testing after porting to Sydney. But that was only by chance, because I had to deal with old datasets. I could have easily overlooked the flaw.
You should check if your projects are also affected. For me, the problem is a neckbreaker right now.
I have just written a very simple test program for the Embarcadero support team. If you want, you can have a look at it and test if your code is also affected.
Below are the instructions and the code:
Create a new project.
Creates two buttons and a memo on the main form.
Assign the two OnClick events for the buttons for load and save accordingly
Runs the program and clicks the save button.
Opens the .TXT in the application directory and delete e.g. the last entry of the record.
Click the load button and an EArgumentOutOfBoundsException is thrown.
unit main;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Memo.Types, FMX.StdCtrls, FMX.Controls.Presentation, FMX.ScrollBox,
FMX.Memo;
type
TAnalysisAdditionalData=record {order important for marshaling}
ExampleData0:Real; {00}
ExampleData1:Real; {01}
ExampleData2:String; {02}
ExampleData3:String; {03} {since version 2016-01-01}
ExampleData4:String; {04} {since version 2018-01-01}
ExampleData5:String; {05}
end;
TSHCustomEntity=class(TPersistent)
private
protected
public
GUID:String;
end;
TSHAnalysis=class(TSHCustomEntity)
private
protected
public
AnalysisResult:String;
AnalysisAdditionalData:TAnalysisAdditionalData;
end;
TMainform = class(TForm)
Memo_Output: TMemo;
Button_Save: TButton;
Button_Load: TButton;
procedure Button_SaveClick(Sender: TObject);
procedure Button_LoadClick(Sender: TObject);
private
Analysis:TSHAnalysis;
procedure Marshal(Filename:String);
procedure Unmarshal(Filename:String);
function GetApplicationPath: String;
function GetFilename: String;
protected
procedure AfterConstruction;override;
public
Destructor Destroy;override;
property ApplicationPath:String read GetApplicationPath;
property Filename:String read GetFilename;
end;
var
Mainform: TMainform;
implementation
{$R *.fmx}
uses
DBXJSON,
DBXJSONReflect,
System.JSON;
{ TMainform }
procedure TMainform.AfterConstruction;
begin
inherited;
self.Analysis:=TSHAnalysis.Create;
self.Analysis.GUID:='6ed61388-cdd4-28dd-6efe-24461c4df3cd';
self.Analysis.AnalysisAdditionalData.ExampleData0:=0.5;
self.Analysis.AnalysisAdditionalData.ExampleData1:=0.9;
self.Analysis.AnalysisAdditionalData.ExampleData2:='ExampleString0';
self.Analysis.AnalysisAdditionalData.ExampleData3:='ExampleString1';
self.Analysis.AnalysisAdditionalData.ExampleData4:='ExampleString2';
self.Analysis.AnalysisAdditionalData.ExampleData5:='ExampleString3';
end;
destructor TMainform.Destroy;
begin
self.Analysis.free;
inherited;
end;
function TMainform.GetApplicationPath: String;
begin
RESULT:=IncludeTrailingPathDelimiter(ExtractFilePath(paramStr(0)));
end;
function TMainform.GetFilename: String;
begin
RESULT:=self.ApplicationPath+'6ed61388-cdd4-28dd-6efe-24461c4df3cd.txt';
end;
procedure TMainform.Button_SaveClick(Sender: TObject);
begin
self.Marshal(self.Filename);
end;
procedure TMainform.Button_LoadClick(Sender: TObject);
begin
if Analysis<>NIL then
FreeAndNil(Analysis);
self.Unmarshal(self.Filename);
self.Memo_Output.Text:=
self.Analysis.GUID+#13#10+
FloatToStr(self.Analysis.AnalysisAdditionalData.ExampleData0)+#13#10+
FloatToStr(self.Analysis.AnalysisAdditionalData.ExampleData1)+#13#10+
self.Analysis.AnalysisAdditionalData.ExampleData2+#13#10+
self.Analysis.AnalysisAdditionalData.ExampleData3+#13#10+
self.Analysis.AnalysisAdditionalData.ExampleData4+#13#10+
self.Analysis.AnalysisAdditionalData.ExampleData5;
end;
procedure TMainform.Marshal(Filename:String);
var
_Marshal:TJSONMarshal;
_Strings:TStringlist;
_Value:TJSONValue;
begin
_Strings:=TStringlist.Create;
try
_Marshal:=TJSONMarshal.Create;
try
_Value:=_Marshal.Marshal(Analysis);
_Strings.text:=_Value.ToString;
finally
if _Value<>NIL then
_Value.free;
_Marshal.free;
end;
_Strings.SaveToFile(Filename);
finally
_Strings.free;
end;
end;
procedure TMainform.Unmarshal(Filename:String);
var
_Strings:TStrings;
_UnMarshal:TJSONUnMarshal;
_Value:TJSONValue;
begin
if FileExists(Filename) then begin
_Strings:=TStringlist.create;
try
_Strings.LoadFromFile(Filename);
try
_Value:=TJSONObject.ParseJSONValue(_Strings.Text);
_UnMarshal:=TJSONUnMarshal.Create;
try
try
self.Analysis:=_UnMarshal.Unmarshal(_Value) as TSHAnalysis;
except
on e:Exception do
self.Memo_Output.text:=e.Message;
end;
finally
_UnMarshal.free;
end;
finally
if _Value<>NIL then
_Value.free;
end;
finally
_Strings.free;
end;
end;
end;
end.
To solve the problem temporarily, I have the following quick solution for you:
Make a copy of the standard library Data.DBXJSONReflect and name it e.g. Data.TempFix.DBXJSONReflect.
Change all includes/uses in your project accordingly.
After that navigate in Data.TempFix.DBXJSONReflect to line 2993:
jsonFieldVal := TJSONArray(JsonValue).Items[I];
And replace it with the following code:
try
jsonFieldVal := TJSONArray(JsonValue).Items[I];
except
on e:Exception do
if e is EArgumentOutOfRangeException then
continue
else
raise;
end;
After that the whole method should look like this:
function TJSONUnMarshal.JSONToTValue(JsonValue: TJSONValue; rttiType: TRttiType): TValue;
var
tvArray: array of TValue;
Value: string;
I: Integer;
elementType: TRttiType;
Data: TValue;
recField: TRTTIField;
attrRev: TJSONInterceptor;
jsonFieldVal: TJSONValue;
ClassType: TClass;
Instance: Pointer;
begin
// null or nil returns empty
if (JsonValue = nil) or (JsonValue is TJSONNull) then
Exit(TValue.Empty);
// for each JSON value type
if JsonValue is TJSONNumber then
// get data "as is"
Value := TJSONNumber(JsonValue).ToString
else if JsonValue is TJSONString then
Value := TJSONString(JsonValue).Value
else if JsonValue is TJSONTrue then
Exit(True)
else if JsonValue is TJSONFalse then
Exit(False)
else if JsonValue is TJSONObject then
// object...
Exit(CreateObject(TJSONObject(JsonValue)))
else
begin
case rttiType.TypeKind of
TTypeKind.tkDynArray, TTypeKind.tkArray:
begin
// array
SetLength(tvArray, TJSONArray(JsonValue).Count);
if rttiType is TRttiArrayType then
elementType := TRttiArrayType(rttiType).elementType
else
elementType := TRttiDynamicArrayType(rttiType).elementType;
for I := 0 to Length(tvArray) - 1 do
tvArray[I] := JSONToTValue(TJSONArray(JsonValue).Items[I],
elementType);
Exit(TValue.FromArray(rttiType.Handle, tvArray));
end;
TTypeKind.tkRecord, TTypeKind.tkMRecord:
begin
TValue.Make(nil, rttiType.Handle, Data);
// match the fields with the array elements
I := 0;
for recField in rttiType.GetFields do
begin
Instance := Data.GetReferenceToRawData;
try
jsonFieldVal := TJSONArray(JsonValue).Items[I];
except
on e:Exception do
if e is EArgumentOutOfRangeException then
continue
else
raise;
end;
// check for type reverter
ClassType := nil;
if recField.FieldType.IsInstance then
ClassType := recField.FieldType.AsInstance.MetaclassType;
if (ClassType <> nil) then
begin
if HasReverter(ClassType, FIELD_ANY) then
RevertType(recField, Instance,
Reverter(ClassType, FIELD_ANY),
jsonFieldVal)
else
begin
attrRev := FieldTypeReverter(recField.FieldType);
if attrRev = nil then
attrRev := FieldReverter(recField);
if attrRev <> nil then
try
RevertType(recField, Instance, attrRev, jsonFieldVal)
finally
attrRev.Free
end
else
recField.SetValue(Instance, JSONToTValue(jsonFieldVal,
recField.FieldType));
end
end
else
recField.SetValue(Instance, JSONToTValue(jsonFieldVal,
recField.FieldType));
Inc(I);
end;
Exit(Data);
end;
end;
end;
// transform value string into TValue based on type info
Exit(StringToTValue(Value, rttiType.Handle));
end;
Currently I have a form that captures login data, a form with a TIWDBGrid that is supposed to return any hosts that are associated with the user_id that is created when I login from my mysql database, and a shared data module.
Below is my code for my login page
unit login_unit;
interface
uses
Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes, IWCompButton,
IWCompLabel, Vcl.Controls, IWVCLBaseControl, IWBaseControl, IWBaseHTMLControl,
IWControl, IWCompEdit;
type
Tlogin_form = class(TIWAppForm)
enter_usermame_TIWEdit: TIWEdit;
enter_password_TIWEdit: TIWEdit;
Username: TIWLabel;
Password: TIWLabel;
login_TIWButton: TIWButton;
returned_user_id_TIWEdit: TIWEdit;
procedure login_TIWButtonClick(Sender: TObject);
public
end;
implementation
{$R *.dfm}
uses email_data, host_lookup_unit;
procedure Tlogin_form.login_TIWButtonClick(Sender: TObject);
var
host_lookup_form:Thost_lookup_Form;
begin
email_data_DataModule.Login_userProc.Prepare;
email_data_DataModule.Login_userProc.ParamByName('user_name_').Value := enter_usermame_TIWEdit.Text;
email_data_DataModule.Login_userProc.ParamByName('pass_word_').Value := enter_password_TIWEdit.Text;
email_data_DataModule.Login_userProc.Execute;
email_data_DataModule._user_id := email_data_DataModule.Login_userProc.ParamByName('user_id_').Value;
returned_user_id_TIWEdit.Text := email_data_DataModule.Login_userProc.ParamByName('user_id_').Value;
email_data_DataModule.Hosts_requested_frm_user_idProc.Prepare;
email_data_DataModule.Hosts_requested_frm_user_idProc.ParamByName('user_id_').Value := email_data_DataModule._user_id;
email_data_DataModule.Hosts_requested_frm_user_idProc.Execute;
thost_lookup_form.Create(Self).Show;
end;
initialization
Tlogin_form.SetAsMainForm;
end.
My host_look up page has a TIWDBGrid component and it looks like the following:
unit host_lookup_unit;
interface
uses
Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes, Vcl.Controls,
IWVCLBaseControl, IWBaseControl, IWBaseHTMLControl, IWControl, IWCompGrids,
IWDBGrids, IWCompButton;
type
Thost_lookup_Form = class(TIWAppForm)
IWDBGrid1: TIWDBGrid;
public
end;
implementation
{$R *.dfm}
uses email_data;
end.
I made sure that the DataSource option was set to email_data_DataModule.hosts_table_requested_TDataSource
And finally the code for my data module is as follows:
unit email_data;
interface
uses
Forms,
SysUtils, Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error,
FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool,
FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MySQL, FireDAC.Phys.MySQLDef,
FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf,
FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client;
type
Temail_data_DataModule = class(TDataModule)
EmaildbConnection: TFDConnection;
Login_userProc: TFDStoredProc;
hosts_table_requested_TDataSource: TDataSource;
Hosts_requested_frm_user_idProc: TFDStoredProc;
private
public
_user_id : integer;
end;
function email_data_DataModule:Temail_data_DataModule;
implementation
{$R *.dfm}
uses ServerController;
function email_data_DataModule:Temail_data_DataModule;
begin
result := UserSession.email_data_DataModule;
end;
end.
How can I make sure to populate the data from the Hosts_requested_frm_user_idProc to my IWDBGrid?
Thanks in advance and sorry for the long post
There are a few issues with your application:
First, all your forms need to have WebApplication object as the owner, so change your line where you create your IWForm to
procedure Tlogin_form.login_TIWButtonClick(Sender: TObject);
var
host_lookup_form:Thost_lookup_Form;
begin
...
thost_lookup_form.Create(WebApplication).Show;
end;
Second, I think you shouldn't be using a stored proc to retrieve data, but a query object. If you are using FireDAC consider changing it to a TFDQuery which will retrieve a result set.
Also, you must put your TDataSource in the same form where the IWDBGrid is, and connect them via IWDBGrid.DataSource property.
Add the unit where the DataModule is declared to the uses clause of the IWForm (in the interface section), and declare a field of the form. So you should have something like this:
unit host_lookup_unit;
interface
uses
Classes, SysUtils, IWAppForm, IWApplication, IWColor, IWTypes, Vcl.Controls,
IWVCLBaseControl, IWBaseControl, IWBaseHTMLControl, IWControl, IWCompGrids,
IWDBGrids, IWCompButton,
email_data; // <- Include your DM here
type
Thost_lookup_Form = class(TIWAppForm)
IWDBGrid1: TIWDBGrid;
hosts_table_requested_TDataSource: TDataSource;
private
FDataModule: Temail_data_DataModule;
public
end;
implementation
{$R *.dfm}
procedure Thost_lookup_Form .host_lookup_FormCreate(Sender: TObject);
begin
FDataModule := email_data_DataModule; // set your field referencing the DM here and use it within your form. Don't use the email_data_DataModule() function anymore!
hosts_table_requested_TDataSource.DataSet := FDataModule.Login_userQuery; // Connect your DataSource and your DataSet, via code. This is the best way to do it!
end;
I also strongly suggest that you remove the logic that deals with setting parameters and opening the query from your form. This code belongs to the DataModule!
You should have something like this:
unit email_data;
interface
uses
Forms,
SysUtils, Classes, FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Error,
FireDAC.UI.Intf, FireDAC.Phys.Intf, FireDAC.Stan.Def, FireDAC.Stan.Pool,
FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.MySQL, FireDAC.Phys.MySQLDef,
FireDAC.VCLUI.Wait, FireDAC.Stan.Param, FireDAC.DatS, FireDAC.DApt.Intf,
FireDAC.DApt, Data.DB, FireDAC.Comp.DataSet, FireDAC.Comp.Client;
type
Temail_data_DataModule = class(TDataModule)
EmaildbConnection: TFDConnection;
Login_userQuery: TFDQuery;
Hosts_requested_frm_user_idQuery: TFDQuery;
private
F_user_id: Integer;
public
function SetUserNameAndPassword(const AUserName, AUserPassword: string): Integer;
end;
function email_data_DataModule:Temail_data_DataModule;
implementation
{$R *.dfm}
uses ServerController;
function email_data_DataModule: Temail_data_DataModule;
begin
result := UserSession.email_data_DataModule;
end;
function Temail_data_DataModule.SetUserNameAndPassword(const AUserName, AUserPassword: string): Integer;
begin
Login_userQuery.Prepare;
Login_userQuery.ParamByName('user_name_').Value := AUserName;
Login_userQuery.ParamByName('pass_word_').Value := AUserPassword;
Login_userQuery.Open;
F_user_id := Login_userQuery.ParamByName('user_id_').Value;
Result := Login_userQuery.ParamByName('user_id_').Value;
Hosts_requested_frm_user_idQuery.Prepare;
Hosts_requested_frm_user_idQuery.ParamByName('user_id_').Value := F_user_id;
Hosts_requested_frm_user_idQuery.Open;
end;
end.
all you need to do now is build and run the application. It should work.
Note: All code above is untested (I wrote it in Notepad, not in Delphi IDE) so it might have typos and some other errors.
How do I get all the username values from the image below and can convert them into TStringList, strings or TMemo?
I tried the following code but it didn't work.
with q3 do
var txResul:stringlist
begin
Close;
SQL.Clear;
SQL.Add('SELECT*FROM user');
Open;
Next;
end;
txtResult.Add(q1.FieldByName('username').AsString);
Assuming your screenshot is a dataset you call do something like this:
procedure GetUserNames(DataSet : TDataSet; StringList : TStringList);
var
Field : TField;
begin
Field := DataSet.FieldByName('username');
StringList.BeginUpdate;
try
DataSet.DisableControls;
try
DataSet.First;
while not DataSet.Eof do begin
StringList.Add(Field.AsString);
DataSet.Next;
end;
finally
DataSet.EnableControls;
end;
finally
StringList.EndUpdate;
end;
end;
You might use it like this
procedure TForm1.GetUsers;
var
TL : StringList;
begin
TL := StringList.Create;
try
GetUserNames(MyTable, TL);
Memo1.Lines.Text := TL.Text;
finally
TL.Free;
end;
end;
Btw, if you changed the second parameter of GetUserNames to a TStrings, as in GetUserNames(DataSet : TDataSet; Strings : TStrings) you could pass Memo1.Lines to it directly.
I have this JSON data:
[
{
"Name":"val1",
"Age":"25"
},
{
"Name":"Vtya",
"Age":"24"
},
{
"Name":"fgani",
"Age":"21"
},
{
"Name":"Shami",
"Age":"21"
},
{
"Name":"Slakf",
"Age":"22"
}
]
I wrote this code to parse the data and add the Name value to a Combobox:
procedure TJSON_Sample.FormCreate(Sender: TObject);
var
LJsonArray: TJSONArray;
LJsonValue, LITEM: TJSONValue;
lJsonData: string;
ljsPair: TJsonPair;
begin
LJsonArray := TJSONObject.ParseJSONValue(TEncoding.
Default.GetBytes(lJsonData), 0) as TJSONArray;//lJsonData contains the above mentioned JSON data
try
for LJsonValue in LJsonArray do
begin
for LITEM in TJSONArray(LJsonValue) do
begin
cmbBox_Name.Items.Add(TJsonPair(LITEM).JsonValue.Value);
end;
end;
finally
LJsonArray.Free;
end;
end;
When I run this, it is adding all of the Names and Ages to the Combobox. Can someone please help me in adding the Names only?
Your code is looping fine through your JSON. Your problem is to get just the 'Name' value when adding the item to the combobox.
Try GetValue('Name') instead of the whole JSONValue.Value.
procedure TJSON_Sample.FormCreate(Sender: TObject);
var
LJsonArray: TJSONArray;
LJsonValue, LITEM: TJSONValue;
lJsonData: string;
ljsPair: TJsonPair;
begin
LJsonArray := TJSONObject.ParseJSONValue(TEncoding.
Default.GetBytes(lJsonData), 0) as TJSONArray;//lJsonData contains the above mentioned JSON data
try
for LJsonValue in LJsonArray do
begin
for LITEM in TJSONArray(LJsonValue) do
begin
cmbBox_Name.Items.Add(TJsonObject(LITEM).GetValue('Name').Tostring);
end;
end;
finally
LJsonArray.Free;
end;
end;
This Solved my request
procedure TJSON_Sample.FormCreate(Sender: TObject);
var
LITEM, lJsonValue: TJSONValue;
lJsonData: string;
begin
lJsonValue := TJSONObject.ParseJSONValue(TEncoding.
Default.GetBytes(lJsonData), 0);//lJsonData contains the above mentioned JSON data
if lJsonValue <> nil then
try
begin
for LITEM in lJsonValue as TJSONArray do
begin
cmbBox_Name.Items.Add(((LITEM as TJSONObject).Get('Name') .JsonValue as TJSONString).Value);
end;
end;
finally
lJsonValue.Free;
end;
end;
I would consider using the Items.AddObject method instead, and use Items.Object[ComboBox1.ItemIndex] on the OnChange event of the combo-box.
Here is almost the same code, but I add BeginUpdate/EndUpdate for combobox items and use generic methods to avoid type casting.
procedure TJSON_Sample.FormCreate(Sender: TObject);
var
LJson, LItem: TJSONValue;
lJsonData: string;
begin
cmbBox_Name.Items.BeginUpdate;
try
cmbBox_Name.Items.Clear;
LJson := TJSONObject.ParseJSONValue(TEncoding.
Default.GetBytes(lJsonData), 0);//lJsonData contains the above mentioned JSON data
if Assigned(LJson) then
begin
for LItem in LJson as TJSONArray do
cmbBox_Name.Items.Add(LItem.GetValue<string>('Name'));
end;
finally
cmbBox_Name.Items.EndUpdate;
end;
end;
There is this link How do I Invoke a procedure when inside another procedure in Pascal But its not exactly my case.
procedure TForm1.Button1Click(Sender: TObject);
var
[...]
begin
// click on button
[...]
end;
and I have this procedure
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
// on double click in flags
[the same code like above]
end;
i tryed this but it does not work
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
TForm1.Button1Click;
end;
then I tryed this
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
TForm1.Button1Click(Sender: TObject);
end;
it also does not work
Can somebody please help me ?
Just call it directly, using either nil or another component as the Sender:
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
Button1Click(nil);
end;
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
Button1Click(CheckListBox2);
end;
Note you don't use the classname (or variable name) of the form itself, since you're calling from the current instance of the form. IOW, do not use TForm1 or Form1 inside of a class method; that limits you to a specific instance of the form instead of being available to all instances. If you need to qualify it, use Self, as in Self.Button1Click(nil);.
Try this
procedure TForm1.CheckListBox2DblClick(Sender: TObject);
begin
TForm1.Button1Click(Sender);
end;