Trying to save a .bmp from PC to a database blob field - mysql

I'm trying to save a .bmp from my PC to a database that contains a blob field.
I am currently working with code from here:
How to insert image into database using TADOQuery Component Only
I've created a new form and added necessary components there.
This is how the form looks like:
It contains the following: 3 TButton, 1 TOpenDialog and 1 TImage
Button Salveaza (Save) is Button3 and has ModalResult set to mrOk
Button Incarca Imagine (Load Image) is Button1
Button Cancel is Button2, has Cancel property ticked and has ModalResult set to mrAbort
The code for the Incarca Imagine (Button1) button is this:
procedure TaddImagineForm.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
Image1.Picture.LoadFromFile(OpenDialog1.FileName);
end;
end;
The code for button named Salveaza (Button3) is:
procedure TaddImagineForm.Button3Click(Sender: TObject);
var
Field: TBlobField;
Stream: TStream;
begin
if dbmodule.comenziQuery.Active and (Image1.Picture.Graphic <> nil) then
begin
dbmodule.comenziQuery.Insert;
Field := TBlobField(dbmodule.comenziQuery.FieldByName('pscreen')); // ensure it ís a blob
Stream := dbmodule.comenziQuery.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
dbmodule.comenziQuery.Post;
end;
end;
end;
The TSQLQuery I'm using (named comenziQuery) is located on a Data module, along with other things I'm using (like DataSource, DataSet, SQLConnection and so on..) the Data module is named dbmodule
The column in the database that should hold the .bmp image is named pscreen and is set as a mediumblob type.
What should happen (in probably my newbie point of view)
The blob field named pscreen for the selected row should now contain the .bmp I selected previously with my TOpenDialog, by pressing the Incarca Imagine button
What's actually hapenning
Once I click the Save button the form closes but the selected row doesn't get updated with the bmp image in it's blob field. No error, no warning, nothing. The field remains NULL for that row.
EDIT
Thanks to Dsm in the comments he pointed out that I'm using an insert, which adds a new record, not updates the one I'm selecting.
I'm referring to this line: dbmodule.comenziQuery.Insert;
Need to change the code somehow to update the record I'm selecting.
Extremely new to Delphi/SQL so I do apologize if it seems I'm banging my head against a wall and doing the exact opposite.
I'm using Rad Studio 10 Seattle, the database is MYSQL, the database components are located on a data module named dbmodule and contain the following: TSimpleDataSet, TSQLQuery, TDataSource, TSQLConnection - they are dbExpress components.
Thank you!

The following code worked and was successful in providing the functionality that I needed
procedure TaddImagineForm.Button3Click(Sender: TObject);
var
Field: TBlobField;
Stream: TStream;
begin
dbmodule.comenziDataSet.Active := True;
if (Image1.Picture.Graphic <> nil) then
begin
dbmodule.comenziDataSet.Edit;
Field := TBlobField(dbmodule.comenziDataSet.FieldByName('pscreen')); // ensure it ís a blob
Stream := dbmodule.comenziDataSet.CreateBlobStream(Field, bmWrite);
try
Image1.Picture.Graphic.SaveToStream(Stream);
finally
Stream.Free;
dbmodule.comenziDataSet.Post;
end;
end;
end;
end.
Just replaced using the Query with using the DataSet and that seems to have solved it, also my original post / question was wrong as I've been confusing the problems. Still, good for anyone going through the same.
Thanks to Sertac Akyuz

Related

How to show users first and last name in other form when I click on his id or data

I am trying to "connect two forms with mysql" I can't explain it very well.
I want to show users first and last name in other form when I click on him ( Click on his ID or ID Održ or first name or last name.)
How can I do that with MySQL? I am beginner in delphi and MySQL.
This is purely related to Delphi and not the DBMS (MySQL or others). What you are trying to achieve is showing data from your main form's dataset on a second form for details (shown as modal).
You need to be more specific about your implementation :
The location of the dataset : on your main form or on an independent DataModule ?
Also, you didn't specify how the values of selected record will be used in the detail form : In labels, variables, other DB-aware controls ?
Is there a bidirectionnal relationship (Editing on the detail form will edit the record on the main form) ?
Here are the possible steps for your case :
Suppose your dataset control is named ''Dataset'', your main form is ''Form1'', and the detail form is ''Form2''.
First :
If your dataset is on your main form, to avoid circular dependency you have to declare :
The detail form's unit in the Implementation uses a section of the main form's unit.
The main form's unit in the Interface uses a section of the detail form's unit.
If your dataset is on an independent "DataModule", then you have to declare :
The detail form's unit in the Implementation uses a section of the main form's unit.
The DataModule's unit in the Interface uses a section of units of both forms.
Second :
Go to the DBGrid "OnCellClick" event (since you only want to click on the cell), write a code to check the column's FieldName if it is ''Id'' or ''Last Name'' or whatever you want, then show the detail form (ShowModal)
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
//Add whatever fields you want
If (Column.FieldName = 'Id') or (Column.FieldName = 'Last Name') then
Form2.ShowModal;
end;
Third :
In the detail form, there are two possible Implementations :
If you have DB-aware controls (TDBEdit, TDBLabel, ...), then you can set their ''DataSource'' and DataField'' properties to get and exchange data with the dataset, for example ''Form1.Dataset'' or ''DataModule1.Dataset''. And the data will be refreshed everytime the detail form is shown.
If you want to use the values of the selected records in variables or a custom logic (like changing a TLabel's caption to something like ''User is %s with id %u'', or as foreign key for filtering another dataset), then you have to get and set those values in the detail form ''OnShow'' event, like in this example :
procedure TForm2.FormShow(Sender: TObject);
begin
Label1.Caption := Format('Details of %s %s - Id : %u', [Form1.Dataset.FirstNameField.AsString, Form1.Dataset.LastNameField.AsString, Form1.Dataset.IdField.AsInteger]);
end;
Or like this :
procedure TForm2.FormShow(Sender: TObject);
var
FirstName, LastName: string;
Id: Integer;
begin
FirstName := Form1.Dataset.FirstNameField.AsString;
LastName := Form1.Dataset.LastNameField.AsString;
Id := Form1.Dataset.IdField.AsInteger;
end;
Fourth :
There is a known issue, the second form ''OnShow" event is fired only on the first call to ''ShowModal'' after form creation, and not in subsequent calls.
As a workaround, you have to either release or hide the detail form when you close it.
You can do this through the detail form ''OnClose'' event, by setting a value for the close action (''caFree'' or ''caHide'').
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caHide;
end;
Fifth :
If you want to update the current record from the detail form, you have to put a control (like a button) for validation in the detail form with an "OnClick" event handler that will commit the changes to the dataset and close the detail form.
There is also the form's ''ModalResult'' property that, when assigned a non-zero value, will close the modal form and return that value to the function ''ShowModal'' called in the main form :
If you use this property, then the validation button on the detail form must assign the returned value, and on the main form you have to check the returned value and receive updated values as variables from the detail.
But you can also avoid using it in order to keep the update logic on the detail form.
If you call the Close method in a modal form, then "ModalResult" is automatically set to "mrCancel".
Here is an example for updating the record without need for ''ModalResult''property (if your dataset is on a DataModule, then replace "Form1" with the name of the DataModule) :
procedure TForm2.BtnSaveClick(Sender: TObject);
begin
try
Form1.Dataset.Edit;
try
Form1.Dataset.FirstNameField.AsString := EditFirstName.Caption;
Form1.Dataset.LastNameField.AsString := EditLastName.Caption;
Form1.Dataset.Post;
except
Form1.Dataset.Cancel;
end;
finally
Close;
end;
end;

Is there a better way than this to stop a DBgrid flickering with time consuming updates?

Can anyone offer advice on how to achieve what I want in the situation below?
(I wonder whether theads might help but haven't used them before.)
In my Delphi application I have a query running against an external MYSQL database over the Internet.The results of the query is shown in a DBGrid (at most 50 rows).
The user clicks a button to do a 'web check', then the following happens...
First I set one field of the dataset (web_response) to the empty string to clear out any existing data showing there in the DBGrid.
Then for each row in the dataset I extract the value of one field (FieldA), pass it to a function, and set the value of another field (web_response) to the result of that function.
The function itself uses IdHTTP to perform a search on a different remote web site using the parameter passed and returns a response string. That process takes around 1 to 2s.
The effect I want is for the grid to have all the web response fields 'instantaneously' cleared, then row by row the web response field gets set to a value, with each value appearing as it is set.
The code below works correctly but does not quite give the effect I need . I'm wondering if using threads somewhere - instead of application.processmessages might improve things.
The effect I get at the moment is the grid goes completely blank for a second or two and then reappears with the web response column blank.
Then the rows get updated with the web response at about the rate of one row every 1s but with the grid flickering violently each time a new response is added.
If threads won't help, is there a better way to do what I am doing?
The code I use at the moment (with identifiers changed to protect the innocent)
//empty any preexisting web responses
//disable controls to stop the DBgrid flickering while we clear out existing web responses
DBGrid1.DataSource.DataSet.DisableControls;
MyQuery1.First;
while not MyQuery1.Eof do
begin
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := '';
MyQuery1.Next;
end;
DBGrid1.RefreshData; //show cleared grid again
DBGrid1.DataSource.DataSet.EnableControls;
//For each row, check FieldA on the web and show response
MyQuery1.First;
while not MyQuery1.Eof do
begin
DataToCheck := MyQuery1.FieldByName('FieldA').AsString ; //get data to check
//get the web response and put into dataset
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := GetWebCheckResponse(DataToCheck);
Application.ProcessMessages; //,'cos the loop is slow <<-- can I get rid of this and use threads?
DBGrid1.RefreshData; //show the response we just put in dataset
MyQuery1.Next;
end;
Been more than 7 years since I last touched Delphi and we were not allowed to use data aware components so I might be giving you wrong advise here. However it appears that you are refreshing the grid too often. Especially you are refreshing the grid in a loop.
I would suggest changing the code to this:
DBGrid1.DataSource.DataSet.DisableControls;
MyQuery1.First;
while not MyQuery1.Eof do
begin
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := '';
MyQuery1.Next;
end;
//For each row, check FieldA on the web and show response
MyQuery1.First;
while not MyQuery1.Eof do
begin
DataToCheck := MyQuery1.FieldByName('FieldA').AsString ; //get data to check
//get the web response and put into dataset
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := GetWebCheckResponse(DataToCheck);
Application.ProcessMessages; //,'cos the loop is slow <<-- can I get rid of this and use threads?
MyQuery1.Next;
end;
DBGrid1.DataSource.DataSet.EnableControls;
DBGrid1.RefreshData; //show the response we just put in dataset
You might want to show a dialog saying processing and not show the grid till all is done. You might want to look at the DBGrid.BegingUpdate() and DBGrid.EndUPdate() if memory serve me right.
I would just use progress bar with progressbar1.repaint; in the loop to refresh just progress, instead of application.processmessages;
DBGrid1.DataSource.DataSet.DisableControls;
MyQuery1.First;
while not MyQuery1.Eof do
begin
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := '';
MyQuery1.Next;
end;
DBGrid1.DataSource.DataSet.EnableControls;
DBGrid1.RefreshData;
Application.ProcessMessages;
//For each row, check FieldA on the web and show response
MyQuery1.First;
while not MyQuery1.Eof do
begin
DataToCheck := MyQuery1.FieldByName('FieldA').AsString ; //get data to check
//get the web response and put into dataset
MyQuery1.Edit;
MyQuery1.FieldByName('web_response').AsString := GetWebCheckResponse(DataToCheck);
MyQuery1.Next;
DBGrid1.RefreshData;
Application.ProcessMessages;
end;
Cheers,
Pham

Why is the BSON Null?

Why is it that when I try and do something very similar to the TMongoWire demo program to load a document, I get a different result? On create of a page, I want to get all the company names and load them (eventually) into a combobox. This is the code I am playing with:
d:=BSON;
q:=TMongoWireQuery.Create(MongoWire);
try
q.Query('mwx1.companies',nil);
while q.Next(d) do
begin
s := BsonToJson(d);
sl.add(d['CompanyName']);
sl.Add(TBSONDocument(d).item['CompanyName'])
end;
finally
q.Free;
end;
At the point where I am assigning the JSON to S, the JSON is fully correct and the CompanyName has data in it. That line was there for testing only. But the next two lines both produce nothing (tried various ways to get the data) because it says that the value is null. If I inspect TBSONDocument(d) it shows all the correct information. So I am baffled as to why it isn't working. Any clues?
It starts out as an empty BSON, but when it's in the loop for the first iteration it contains the BSON of
'{"_id":"ObjectID(\"524547512dcf91c1dc7476cb\")","Email":"2324","CompanyName":"T‌​est 1","Addr1":"fs","Addr2":"ertert","City":"iukuiuiku","State":"uikuiku","Zip":"dsf‌​","Country":"ff","Phone":"fdsd","SalesPerson":"sds","ContactPhone":"sdf","Contact‌​Email":"fsdf","ContactName":"f","DateCreated":"g2","website":"34","SMS":"23","Log‌​o":"23423","Status":"qwqw","Keywords":"3423","Shortcode":"qwqw","ParentID":"asda"‌​}'

Lazarus, can't get DB Update working. How can I preview whats being submitted?

Hi I have a form setup using TMySQL51Connection, TSQLTransaction & TSQLQuery modules, it retrieves info from the DB without issue but I'm having problems with updates.
The DB is pretty large so I'm starting with just the 1st couple of rows, once they're working I'll extend the query.
My TSQLQuery.UpdateSQL is as follows
UPDATE table SET
ContactFirst = :ContactFirst,
ContactSur = :ContactSur
WHERE AccountID = :AccountID
Then I have a button in my form, the onCLick event contains:
begin
accSelect.Edit;
accSelect.Post;
accSelect.ApplyUpdates;
dbTransaction.CommitRetaining;
sqlbl1.Caption := accSelect.UpdateSQL;
end;
Clicking the buttons does precisely nothing with the DB, it generates no error messages, just updates the caption on sqlbl1. Is there anyway to preview what Lazarus is sending to the DB with values included so I can track down whats going wrong?
I tried adding a logging event to the SQLConnection but couldn't work out how to get it generating logs.
From my experience, the Edit, Post and ApplyUpdates methods are used in conjunction with a TClientDataSet. In that case you would simply assign new values to the fields in the CDS (after navigating to the record you want to Edit) then Post those changes (no need for an Update SQL statement). Something like this...
MyCDS.Edit;
MyCDS.FieldByName('ContactFirst').Value := sContactFirstName;
MyCDS.FieldByName('ContactSur').Value := sContactSurname;
MyCDS.Post;
MyCDS.ApplyUpdates;
Alternatively, you could use a Query component, write the UPDATE SQL into the SQL property, and use ExecSQL or whatever method has been implemented for that component (there are many database access components that each have their own idiosyncrasies)
Here's some code off the top of my head. Please excuse me but I'm not familiar with Lazarus specifics - it's basically Delphi code.
MySQLQuery.SQL.Clear;
MySQLQuery.SQL := 'UPDATE MyTable
SET ContactFirst = :ContactFirst,
ContactSur = :ContactSur
WHERE AccountID = :AccountID';
MySQLQuery.Params.ParamByName('ContactFirst').Value := sContactFirstName;
MySQLQuery.Params.ParamByName('ContactSur').Value := sContactSurname;
MySQLQuery.Params.ParamByName('AccountID').Value := iAccountID;
try
MySQLQuery.ExecSQL;
ShowMessage('Update succeeded');
except on e: Exception do
ShowMessage(e.Message);
end;
So it might be that you've ended up using half of both methods and neither of them completely.

How to change values of a mysql database via dbgrid?

Hey guys good morning,
i got a DBGrid and the UniDac components. I a use a popupmenu and select a row. I fill via the onclick event from the popupmenu a new form with my data in my TEdit.
Now the problem is, that i want to edit my data which i selected from the dbgrid.
This code works until dbgrid is refreshed and then the old values are back again in my dbgrid. How can i change it for the mysql table too not only for the dbgrid?
My actually Code:
FQuery.Edit;
FQuery.FieldByName('CfgUID').AsString := Edit4.Text;
FQuery.FieldByName('CfgMod').AsString := Edit1.Text;
FQuery.Post;
The solution was to disable CachedUpdates or call ApplyUpdates after Post.