After updating the record set the Screen must update - informix

In informix 4gl(genero 4JS) how can I refresh the screen after updating the record set in the database? Right now I can only update the record but the screen is not updating. I think I am missing something. The following set is working fine. after updating I need to refresh the screen with new status.
update person set
person = m_folder.person,
date = m_folder.date,
time = m_folder.time,
status = m_folder.status,
userid = m_folder.userid,
where rowid = g_rowid

After you've updated the database, your program must redisplay the data (possibly after fetching the updated values). I4GL changes the screen when you DISPLAY to it (or INPUT from it); it changes the database when you execute SQL; it never automatically does one because you've done the other (which is actually good; it gives you control over everything).

Try the CALL ui.Interface.Refresh() instruction.
If it doesn't work then Jonathan Leffler is right: you have to use some dialog-type instruction (DISPLAY or INPUT) to display it, like DISPLAY BY NAME m_folder.*

Related

Refresh one row in cxGrid

I have seen there is a problem refreshing only current row if the data are changed in another form (and DataSet too) or even if the data are changed on server side (in trigger or from another user).
So i find solution that partially work with DevExpress's cxGrid and have following issue.
frm:=TfrmEdb01.Create(Self); // create edit-form
try
frm.LoadData(0); // do the insert in TAdQuery
frm.ShowModal; // Show edit form
// after closing an Edit-Form, make a new record in cxGrid
row:=tv01.dataController.InsertRecord(tv01.Controller.FocusedRecordIndex);
// for each column in grid...
for col:=0 to tv01.DataController.ItemCount-1 do
begin
// ...get its FieldName
sFld:=tv01.DataController.GetItemFieldName(col);
// and if this field exist in edit-form's Query
if frm.q01.FindField(sFld)<>nil then
//then assign this value to the newly created row in the grid.
tv01.DataController.Values[row,col]:=frm.q01.FieldByName(sFld).Value;
end;
finally
frm.Free;
end;
And realy, when I step out from the edit-form there is a New row created in the cxGrid. Problem is in that:
- if is double-clicked (to open edit-form again) then the previous record is opened. It seems to me the Data acctualy did not updated in Query object, only in GridView... maybe I should use values from Grid instead of Query object.
- if select another record (scroll them up and down), and then want to select again this new record, then it can not be focused at all. Only if I reload whole dataSet, then this new record can be selected same as any other.
Cheers!
p.s. To clearify a problem, I will provide whole test-project. There is also SQL script to create a table in the database, and AnyDac connection must be set to Your database.
There is also an image thate will/should ilustrate a problem.
You have call post to save the changes to the underlying dataset. Do it just before finally.
tv01.DataController.Post();
See the help for TcxCustomDataController.Post for more details.

DataSnap using AutoInc key and refresh current record only after insert

I've not been able to find an answer on this anywhere. Using Delphi XE7 with TClientDataSet, DataSnap & SQL Server. I need to insert a record, apply updates and then refresh that record so I can get the Id and assign it to my object. Seems pretty basic requirement, but on the contrary it is proving to be a royal pain.
I've found the obvious stuff on EDN, SO and Dr Bob:
http://edn.embarcadero.com/article/20847
DataSnap and the autoinc field
http://www.drbob42.com/examines/examinC0.htm
However these seem to focus on a "Refresh" of the TClientDataSet to re-fetches the entire table/query. Whilst this does actually resolve the Id field itself (good!), it also moves the cursor off the current record which was just inserted and so I'm not able to get the Id and assign it to my object. Also, for performance over HTTP I don't really want to refetch the entire table every time a record is inserted, if there's 10,000 records this will consume too much bandwidth and be ridiculously slow!
Consider the following code:
function TRepository<I>.Insert(const AEntity: I): I;
begin
FDataSet.DisableControls;
try
FDataSet.Insert;
AssignEntityToDataSet(AEntity); // SET'S ALL THE RELEVANT FIELDS
FDataSet.Post;
FDataSet.ApplyUpdates(-1);
FDataSet.Refresh; // <--- I tried RefreshRecord here but it cannot resolve the record
AEntity.Id := FDataSet.FieldByName('Id').AsInteger; // <----- THIS NOW POINTS TO WRONG ROW
finally
FDataSet.EnableControls;
end;
end;
Does anyone know how to achieve this? I need to be able to refresh and stay on the current record otherwise I do not know the Id of the record just created and the GUI cannot stay focused on the current record.
Hopefully something obvious I'm missing.
Cheers.
Rick.
Assuming you can get hands on the new ID inside the AfterUpdateRecord event of your DataProvider, your event handler then may look like this (the current record of DeltaDS is the one just inserted into SourceDS):
if (UpdateKind = ukInsert) then begin
DeltaDS.FindField('Id').NewValue := <TheNewID>;
end;
Make sure to have the poPropogateChanges option set in the provider. This will transfer the changed Id field back to the ClientDataSet.
Now you can get rid of the FDataSet.Refresh call.
SQL Server does allow you to get the last identity it generated in several ways - there's no need to "refresh" the record/query which means re-issuing a SELECT and can generate undesiderable side-effects. You can use SELECT SCOPE_IDENTITY() or use an OUTPUT clause. If the Delphi database driver supports it, TField.AutogenerateValue should accomplish that task automatically (see http://docwiki.embarcadero.com/Libraries/XE7/en/Data.DB.TField.AutoGenerateValue)
Otherwise you have to put that new data into your delta (see Raabe answer - this has to be done on the datasnap server which actually talks to the database) after reading it, so it's sent back to the client. You also need to set properly and TField.ProviderFlags to ensure data are applied correctly (see http://docwiki.embarcadero.com/RADStudio/XE7/en/Influencing_How_Updates_Are_Applied), usually you don't want those field appear in an UPDATE.

Observing changes to database value via KVO

I'm building a messaging application. I update the badge count in the database via a sqlite trigger whenever any operation like insert/delete/read message happens.
Currently, though the value update in the DB happens asynchronously, I have no way to get notified about when the value changes in my application and hence am polling periodically.
Is there some way to setup an observer on a database value/publish some notification when a given value changes?
I know that I can do this easily by first updating the badge count in an in-memory property and then persisting the changes to the DB; but I am not very inclined to do this, since there are too many entry points for this value to change, and I don't want to add a SET property everywhere.
One possible option would be to define a trigger that is only called when this specific value in the database is updated. The trigger should then make a call to a user defined function you create in your app. You use the sqlite3_create_function function to add your own function to SQLite. Your trigger would like something like:
CREATE TRIGGER some_trigger_name
AFTER UPDATE OF some_column ON some_table
FOR EACH ROW BEGIN
SELECT my_custom_fuction();
END;
If needed, you can pass 1 or more arguments to your function.
Though that this might not be an option for you, Core Data does this well.

Locking before save with fixed concurrencymode

I'm learning about concurrency in conjunction with EF4.0 and have a question about the locking pattern used.
Say I configure a fixed concurrency mode on a version number property.
Now say I fetch a record (entity) from the database (context) and edit some property. Version gets incremented and when SaveChanges is called on its context. If the current database (context) version matches the version of the original record (entity) the save continues, otherwise an OptimisticConcurrencyException gets thrown by EF.
Now, my point of interest is the following: between the check of the versions there's always a small period of time, however small, it is there. So in theory someone else could've just updated the record between the comparison and the actual save, thus possibly corrupting the data.
How does this get solved? It feels as if the problem just gets pushed forward.
There is no period of time between checking versions and updating record because the database command looks like:
UPDATE SomeTable
SET SomeColumn = 'SomeValue'
WHERE Id = #Id AND Version = #OldVersion
SELECT ##ROWCOUNT
The check and update is one atomic operation. Rowcount will return 0 if no record with Id = #Id and Version = #OldVersion exists and that zero is translated to the exception.
This can (and probably is) solved using locking hints.
For SQL Server, EF can query (SELECT) from the database WITH UPDLOCK.
This tells the Database Engine that, you want to read a/several records, and nobody else can change those records until you perform an update thereafter.
If you want to see this for yourself, check out the Sql Server Profiler which will show you the queries in real-time.
Hope that helps.
CAVEAT: I can't say for sure that this is the way EF handles this scenario because I haven't checked myself but, certainly if you were going to do it yourself, this is one way to do it.

Why is Entity framework loading data from the db when I set a property?

I have two tables (there are more in the database but only two are involved here).
Account and AccountStatus, an account can have an AccountStatus (active,inactive etc).
I create a new Account and set a couple of properties but when I reach this code:
1. var status = db.AccountStatuses.SingleOrDefault(s => s.ID == (long)AccountStatusEnum.Active);
2. account.AccountStatus = status;
3. db.Accounts.AddObject(account);
The first line executes fine, but when I reach the second line it takes a REALLY long time, and when I step in to the code it seems that every single account is loaded from the database.
I don't see why it should even want to load all the accounts?
We use Entity Framework 4 and Poco and we have lazy loading enabled.
Any suggestions?
Cheers
/Jimmy
You have to be careful which constructs you use to fetch data, as some will pull in the whole set and filter afterword. (aside: the long time delay may be the database being created and seeded, if there isn't one already, it will occur the first time you touch it, likely with a query of some sort. Also remember that when you retrieve a whole dataset, you may in actuality only have what amounts to a compiled query that won't be evaluated until you interact with it).
Try this form instead and see if you have the same issue:
var status = db.AccountStatuses.Where(s => s.ID == (long)AccountStatusEnum.Active);

Resources