Problems with Delphi XE2, DataSnap and Lookup Field - delphi

I have a bit of problem here. I have created a lookupfield in my application server using Delphi XE2 DataSnap technology. On the client side, that field becomes TStringField. Now, the problem is that I loose the lookup functionality on the client side. To top that, I can't change the stringfield on the client side because it is read only (even if I manually turn off the read only property).
I don't want to lookup tables on the client side because I don't want all the data loaded on my client side just to support look up.
I can change the Key field value, but the stringfield lookup text doesnt change unless I apply updates and reload the data.
Users want to see the text change.
What should I do?

Seems you have to review your GUI functionality: lookup fields are really an client side feature. And it needs the lookup source - so to use it on client the lookup table must be loaded. DataSnap guys are very nice here, converting it to an TStringField when transmitting it to the client... I would simply ignore it.
So, if the lookup table is that big, you shouldn't using lookup fields but search UIs - or autocomplete comboboxes which you do queries against the DataSnap Server. Maybe you have to code it manually in the combobox case, I don't know (see if JVCL have something you can use to shortcut the path).
Alternatively, if the lookup table are seldom updated, you can aggresively cache it and have an updating mechanism to detect changes. So you can use the lookup fields the way they were created for.

Long time ago i faced that problem and i found a solution that is a bit complex to analyze here but i try to give some guidelines till i have the time to write a detailed blog post.
The idea consists of info (concerning lookup fields such as field properties, datasets, providers) packaged by the provider as optionalparams at the server side.
At client side a derived TClientDataset can unpack and process these info, create on the fly client datasets that retrieve needed lookup datasets and setup it's lookup fields accordingly.
The process is transparent due to the embedded functionality in the derived client dataset class and the only things to remember is to create that info in the provider's OnGetDatasetProperties event and turn false all provider flags in lookup fields.

Related

Is there a way to automatic load control values to Orbeon Forms?

We've just recently bought and started using Orbeon.
When the user edits a form, and want to save it, he press the save button, and we defined it to send the Orbeon-style XML with all the controls values to my C# REST API. When the user wants to continue editing the form, I call the Orbeon form, and there is a trigger, what fires when page loads, and it starts a REST API call to my C# REST API, to get the control values. Now we have to define map EVERY value. Eg. ControlSurname -> ControlSurname, ControlLastname -> ControlLastname ... etc.
Is there a way, that my C# API gives back the same Orbeon-style XML (maybe some values changed due to the business logic, but not the structure), and Orbeon parses it and put all the control values to its place? (Without mapping all the 87 control?) (It works in the save methon, you dont give a mapping when save...)
You can configure Orbeon Forms to load the initial data from a service. See the section Initial data from service for more on this.
The benefit of this approach is that you won't have to do any the mapping work you were referring to, and the drawback is that you have to make sure that the structure returned by your service corresponds to what the form expects, or your form might end up with missing fields or other problems.

Delphi create User form

I am making a user form in Delphi for documents tracking application. I am interested in functionalities input new entry (record) and view list by... (date, name of document, ID,...).
My problem is that I don't know how to implement these functionalities for more than one user. Currently, I have 5 users. Each user has a unique input data (record) fields (columns) and view fields (columns) of each user are also unique. There could be more users.
So, how to implement these functionalities for this form? How to assign different data (fields) for each separate user for input and view? That is what I don't understand. Is that distributed functionality of an application? If yes, how to achieve it?
Note that I don't want static assigning of a user in application's code, e.g:
if(username='user1') then {
input();
view();
}
else if (username='user2') then {...}
...
because, than, every time there is a new user, developer must go back to the application's code and hard-code it. That is not efficient and is a bad implementation. Rather, I want that to be dynamic (if that is the right term). How to achieve this?
Note: I am using dbExpress tool with MySQL DBMS with RAD Studio XE7 Architect.
If I'm correctly understanding what you are asking, it seems as if you are unfamiliar with the idea of tables/datasets which operate in a so-called Master-Detail relationship. These are very easy to set up in Delphi.
Once you get familar with M->D relationships, I think you'll realise that what you should have been asking about is how to set one up in your app, rather than the problem of hard-coding of individual users into your form.
In your case, what you are missing at the moment is a table of users' details. Let's call that the Users table. Usually this would contain their name, obviously, and some kind of unique identifier (best is a "Primary key" in the Users database table), but NOT, please, their password to access the db, especially not in plain text.
Once your Users table is created, you can create a display grid (TDBGrid) and input/editing form for it.
Then, if you don't have it already, you could set up a grid and editing form for users' documents (which I'm going to refer to as the Documents table).
Once that's done, the main thing left to do is to set up in your Delphi project a Master-Detail relationship between your Users table (the master) and your Documents table (the detail).
If you prefer you can have a single form with two grids, the Users grid and the Documents grid on it, and as you scroll through the Users grid, you'll see that the Documents grid shows only their document records.
The details of how to set up a Master-Detail vary somewhat according to the type of table/dataset you're using so you'll need to search online for the details of how to do it. Broadly, it's a matter of connecting a TDataSource to your Users table and setting the DataSource (or MasterSource) property of your Documents table to point at the Users TDataSource, and then setting a couple of other, table-type-dependent properties of the Documents table.
Every edition of Delphi since well before D7 has come with a demo app, "MastApp" which illustrates how you use Master-Detail relationship amongst a number of tables. I suggest you take a look at the MastApp for your Delphi version and then look into how to set up M->D relationships for the type of Delphi dataset you are actually using.

Binding a irregular URL encoded POST request with Nancy

I'm supposed to make an old sqlite database editable trough a Sketchup Plugin in its WebDialog. Sketchups Ruby is not able to install the sqlite3 gem and since I already need to display the table in a WebDialog, I opted for a micro service with the help of Nancy. The existing Plugin already uses the dhtmlxSuite and its Grid Component is exactly what I need. They even offer a Connector that can send requests based on the actions of the user in the grid.
They also offer a connector for the server side, but that too does not work with sqlite. I already managed to connect to my database, used Dapper to bin the result of an SQL query to an object and return that data with a manually crafted JSON object. Very hacky, but it populates the data successful.
Now the client-Connector sends data manipulated by the user (delete and insert is forbidden) back with an url encoded POST request that looks quite weird:
4_gr_id=4&4_c0=0701.041&4_c1=Diagonale%20f%3Fr%202.07%20X%201.50%20m&4_c2=AR&4_c3=8.3&4_c4=380&4_c5=38.53&4_c6=0&4_c7=0&4_!nativeeditor_status=updated&ids=4
I'm not sure exactly why the hell they would use the row index inside the key for the key-value pairs, but this just makes my life that much harder. The only thing that comes to my mind is extracting the data I'm interested in with a regex, but that sounds even worse than what I did before.
Any suggestions for me how I could map that POST request to something usable?

Need Only New and Updated Entries from ATOM, RSS

Is there an ATOM Client or framework that enables capture of a feed entry EXACTLY once?
If not, what is the best architecture?
We would like to parse an ATOM feed, persisting all syndication feed entries locally as individual records (in database or file system). These records may have to be deleted periodically for efficiency. So client must keep track of which entries it has already looked at, independently - of the said persistence.
Have you looked at Superfeedr? Its a software as a Service platform that does just that: fetches feeds, parsed them and sends the new entries to your endpoints when they're available.
Answering my own, per working solution developed. In one word, the architectural solution to capturing only new and unique entries from a syndication feed is - CACHING.
Specifically, the entries must be stored by the client to support the logic "does the feed have anything new for me?". I believe there is no shortcut to this "client-side" solution.
Conditional-GET is not a complete solution, even if supported server side by the syndicated feed. For instance, if the client client does not send the exact If-Modified-Since time-stamp, the server can ignore the header and simply generate all entries again. Per Chris Berry, Bryon Jacob. Updated 10/27/08,
...a better way to do this is to use the start-index parameter, where the client sets this value to the end-Index, returned in the previous page. Using start-index ensures that the client will never see the same response twice, or miss Entries, since several Entries could have the same "update date", but will never have the same "update index".
In short, there is no standard server side solution guaranteeing "new/unique". The very idea of "uniqueness" is a client-side issue anyway and same opinion may not be shared by the server. From that perspective, it would be impossible for server to satisfy all clients. And, anyway, the question does not pertain to developing a better syndication server, but a smarter client, therefore, Caching is the way to go.
Cache implementation must persist between feed polls and the time-to-live (ttl), time-to-idle (tti) properties of entries stored in cache must be set appropriately to BOTH limit the performance/size of cache AND also to adequately cover the feed's oldest entries between polling cycles. Cache could be memory resident, database, file system or network array. A product like EHCache, ehcache.org, provides just about all the functionality needed.
The feed entries may persisted as-is, but the best (most efficient) method would be to identify contents, or combinations thereof, that make them unique. Methods like serialization in java or Google's Protocol Buffers may be used to create unique compact keys to persist in the cache. In my simple solution, I did not even bother storing the entries, just the keys generated as an MD5 hash of a couple of entry fields by which I defined how an entry would be unique for my purpose.
Hope this flowchart is helpful.

Component published property as array of TQuery

i'm developing a custom component, and i'd like to add a published property that would be an array of TQuery (it should be visible in the object inspector). the main feature would be to drop the component on a form and then visually select the queries that are present on the same form, or on any other project form.
is that doable? from what i've seen till now, you can only programatically use such an array property...
UPDATE
first, thanks for your answer Alex!
second, the chatch is that i have to modify an old app someone else created, so i want to tangle with it as little as possible (actually there's a second app i need to "fix" which i was told is twice as big). now for the details: the app has abou 15 forms for various db operations. as you can imagine each form has 2-3 TQuery objects. the problem is that the user must authenticate with the db in order to execute the queries, thus he knows the db user & pwd which is a security flow.
in order to avoid this, an intermediate system has been introduced. one connects & authenticates with it and requests the necessary db data: user, pwd, and database name. my job is to use this system and autologin to the db. the necessary credentials to access this intermediate system are not considered a security flow so i'll read them from an inifile that depends on the environment where it's deployed: test, pre-production, production.
so i placed a TDatabase component on my form, setting its LoginPrompt property to FALSE. the tricky part however is adjusting each TQuery to the diferent database name for each environment before execution..
dunno if i made myself clear but it's the simplest explaination i managed to come up with
thanks,
G
To make life as simple as possible, you may have to grin and bear it once:
Create a datamodule and make sure it gets instantiated before the main form.
Put your TDatabase component on that data module.
Go through all your forms once and
add the database's data module to its uses clause (can be in implementation section).
Change all your TQuery and other database related components once to use the database component from the data module instead of having their own connection strings.
At run time, login as you described via your TDatabase component et voila, all your components will now use these settings automagically (as they are all connected to your TDatabase instance).
Okay, you've added a TDatabase to your project. Now, fill the "DatabaseName" property of TDatabase with some random name. Every TQuery component in your project also has a "DatabaseName" property and fill in the same name in those properties! Now your database and all it's queries will be connected and you could use the TDatabase object to access them all.
Yes, it can be done but you will have to write your own Property editor with it's own input form to manage the data inside the array. There's plenty of information to be found online. And yes, you could create a component that checks for controls on it's parent, allowing you to access those.
But is it practical? Why do you need an array of TQuery components in design time? Maybe you need to rethink your design first, so you're absolutely sure that you need this functionality. (Besides, what's wrong with using a Data Module to contain your queries?)

Resources