-
Content Count
1264 -
Joined
-
Last visited
-
Days Won
26
Posts posted by David Schwartz
-
-
12 hours ago, Willicious said:Yes, this does remove the error, thanks 🙂
So, what exactly does override do? From what I understand, it applies changes to procedures/functions with the same name that also exist in another unit/class. If override is needed here, then how can I prevent the error in that case?
Yes, I too found this Google result (as I stated in the OP). However, it doesn't resolve the issue because I haven't misspelled anything.
Apologies if I seem to be asking basic questions, I'm very new to both Delphi and programming in general. Being able to ask you guys questions is very helpful, so thank you.
Object-Oriented Programming involves three distinct things: Polymorphism, Inheritance, and Encapsulation.
It seems you are not grounded in these yet. (Don't feel bad, none of us knew how to walk or talk when we were born, either. There's stuff in life that just needs to be learned. 🙂 )
You didn't show the declaration for the TBaseSkillPanel class, so it's unclear if you're inheriting from something else or not. I could guess it's several things, but I'll not go there.
It's either declared like this: TBaseSkillPanel = class
or like this: TBaseSkillPanel = class( TForm ) -- or something other than TForm
The first one is a standalone class (which in Delphi's world is really implied as saying = class(TObject) ), while the second one is derived from some other class.
This is what inheritance refers to -- you're extending the base class by adding more stuff to it and giving that new combined class a different name
If you're inheriting from TForm or some other subclass that defines PanelResize, then it needs to have the virtual or dynamic attribute on its declaration to allow you to then say override but it's not required.
In this case, the error suggests that there either is NOT a PanelResize method in the base class, or it is not tagged with a virtual or dynamic attribute, meaning the override is misplaced -- in fact, it doesn't belong there.
The flip side of this would be where the base class DOES specify virtual and the derived class does NOT specify override on a method with the same name and signature. In this case, the compiler would warn you that the "method in the derived class hides the method of the same name in the base class". Sometimes you want that, in which case instead of override, you need to specify reintroduce to avoid the warning. (This is quite common when you want to use the same method name in the derived class but change its signature, usually by adding more parameters. It's most commonly encountered on constructor Create... methods.)
I suspect you think that adding methods in a derived class requires you to include the override attribute. It's only needed if there's a method in the base class with the same name and signature that has virtual or dynamic specified. That's not correct thinking.
Also, the use of virtual or dynamic (although dynamic is very rarely used) signifies the possibiity of polymorphism, which is an aspect of inheritance that gives you some rather magical abilities.
I suggest you learn about these three topics; they'll help you understand and organize your code much better. They are fundamental to ALL aspects of object-oriented programming, which Delphi embraces quite extensively.
-
New technology always comes with a lot of "noise". If you're not willing to tolerate that "noise", then you can just stand by and wait while others master the underlying technology while simultaneously figuring out how to reduce the "noise level".
-
2 hours ago, Brian Evans said:I worry about the maintenance of applications using some of these cloud services. Sourcing a replacement library/component/backend between major releases or updates is a walk in the park compared to having to replace a cloud service possibly live or at least on the cloud service provider's schedule vs your own.
Time-to-market is my primary driver right now. I can integrate a 3rd-party API in a day or two. Reinventing what they've already built is just not a luxury I can afford at the moment.
-
-
2 hours ago, Giorgi Chapidze said:Does the book mentioned cover all essential topics for going from a beginner to an advanced level? Which one would you buy from the two if needed?
Delphi has always maintained a strong commitment to backward compatibility, so pretty much ANY book you find will be useful for learning Delphi.
At its core, Delphi is basically Pascal with classes added to it. So you can use pretty much any Pascal book as well, at least for the basics. Pascal was created to help teach programming, and books written for that purpose are far more informative about the language features than any book on Delphi is going to be. (It doesn't help that Pascal hasn't been used to teach programming for 20 years or so now, so basic Pascal books haven't been written in ages. And unless you want to learn Modula, you won't find anything that gets into "Pascal with classes". Dephi's "Object Pascal" is still with us today, but was never widely taught in schools.)
So classes add another level of abstraction to basic Pascal. Related to this is Delphi's Run-Time Library, or RTL.
But Pascal's UI never went past readln and writeln that worked on terminals of the era. Today they still work inside of a command shell window, and many people use them to demonstrate simple programs. 🙂
The real "magic" that Dephi brought us was Forms! To learn about forms, you have to dive into the Visual Control Library, or VCL, and that's a very specific set of abstractions that let you build GUI-based apps in Windows.
Over time, a lot of stuff in the VCL has been moved over to the RTL and expanded upon. And in the past several releases, a ton of things have been hijacked from C# and added to Delphi's libs as "Helper Classes". You're not going to find much of anything that describes them other than just diving into the source code for the RTL and parts of the VCL. Maybe the Help files, although over the years, Dephi's "help" files haven't been particularly "helpful" for newer and more complex topics.
From there, you'll get into specific types of classes that are more domain specific, and that's going to be where most books start to diverge. A lot of them will go into DB-specific stuff, and early books talk about things that are pretty much obsolete today -- eg., BDE and frameworks that pre-date the current FireDAC (FD) classes. But a book on Graphics or Games will focus more on using TCanvas and display-specific parts of the VCL as well as mouse, keyboard, and timer events.
In other words, as you get into books about more specialized problem domains, they'll focus on different topics. That's where I'd draw the line between "basic" and "advanced" topics. If you're interested in Games, then a book that goes into detail on working with MS SQL Server isn't going to teach you much.
A lot of us who've been working with Delphi since D1 have a large collection of books we've acquired over the years, and most of them are still useful, believe it or not. If you want to learn about creating components, there were some books written way back in the 90's that are still ideal for learning the basics, and they're hard to come by as well.
A good gauge to use is perhaps the most commonly used thing in all of Delphi -- the basic TStringlist. It has been around forever. It gets a new method or two added here and there, and today it's far more useful and extensive than what it was back in the first release of Delphi. In fact, you could probably write an entire book on ONLY applications of TStringlist. For instance, one thing not many people know is that it can be used to read and write CSV files, and even let you access fields in each record.
As you can see from Marco's book, as huge as it is, it could easily be TWICE the size if it included both details on things that have been around forever as well as on newer features. That's why the older books can be valueable -- they get into details on topics that nobody covers today simply to avoid making the books "too big". The topics are just as valid today as they were way back, but a book that included them would be a couple thousand pages long!
Besides, you can only learn so much by reading books. I've learned far more over the years by reading code written by others than from books. Other programmers will invariably combine things in ways that you'll never see in books, because books just touch on isolated topics, while programs are more complex combinations of many different things and many levels of abstraction. Learning from books is more of a top-down process, while learning PRACTICAL topics is more of a middle-out process.
If you want to challenge yourself to the limit, find something written in another OOP language you're famliar with, like C++, and try rewriting it in Delphi. That will force you to learn more nooks and crannies of the Delphi ecosystem than you'll ever get from any book!
-
On 3/17/2023 at 8:44 AM, Willicious said:@GaryThanks for the suggestion, but tbh I'd like to try doing it as a Windows app. Later, I'll try again following the tutorial as you've suggested, for sure.
I believe the difference here is whether you're using VCL -- which is ONLY Windows -- or FMX -- of which Windows is ONE OF MANY target platforms that can be selected.
That is, with Windows, you can use EITHER VCL or FMX.
-
1
-
-
On 3/21/2023 at 4:12 AM, Henry Olive said:David, Combobox1.Text.AsInteger doesnt compile in D10.3
As Stano said ... there's always StrToInt( Combobox1.Text )
-
9 hours ago, Henry Olive said:Good Day,
I add Customer No & Customer Name in a combobox like below
Combobox1.Items.AddObject(SQLQuery1.Fields[1].asString, Pointer(SQLQuery1.Fields[1].asInteger));
Since the same field value (a numerical string) is being used in both places, all this code is doing is saving you a StrToInt conversion later one, and it's not necessary.
It makes me think ... who in their right mind would put a bunch of numbers into a ComboBox? I'm guessing you have oversimplified your example. But perhaps not.
Assuming not, and given that the ComboBox just has a bunch of numerical strings in it, you just need to say, "Combobox1.Text.AsInteger" to get its numerical VALUE ... when you need it.
Why waste memory by doing the conversion earlier and sticking it into the Obect's array?Besides, the values in Objects are NOT Pointers, they're references to TObject instances. So you should cast them to TObjects, not Pointers. That still doesn't make much sense to me.
Doesn't the basic TComboBox allow Names and Values to be specified? Or is that just the Raize version? Because that's what I'd use. (If not, then I'd use name=value pairs and a custom OnShow method to only display the Name part and then extract the Value part in the OnSelect handler.)
-
Again, I think most of you are missing the point. In any workplace scenario, most code written by inexperienced programmers is checked by more experienced programmers. Also, just because the code passes unit tests doesn't mean it's "accepetable" code, although I'm sure there are organiations that would disagree with that.
The point is ... ChatGPT seems to generate code somewhat on par with newbie programmers. There's a LOT of useful code it generates, and some that's wrong. It may not compile right off the bat, but that doesn't mean it's 100% useless. I can't speak for anybody else here, but while I know that there are lots of eyeballs on code posted to SO, most of it is short and STILL isn't something that can simply be copy-and-pasted into anything without spending time reviewing it and making it "fit in" with your existing code. That seems to be the "ideal" that everybody is holding up and saying, "Well, when it's as good at programming as I am, then I'll consider it worthwhile." I'd say, well bubba ... when it's THAT good, you and I will be out of work.
There are plenty of things on SO where nobody offered up good solutions that ChatGPT can at least help with.
Looking for stuff on SO is like going on a Treasure Hunt, and what you get is often no better than what you can get directly from ChatGPT. The thing is, ChatGPT is not just FASTER, but it will invariably get better over time.
I've hired supposedly "experienced" devs over the years to write relatively small and highly-specific code units for me, and the quality of their code they sent me was mostly pretty low. Most, I'm assuming, couldn't even solve the problem I gave them b/c they just disappeared after a while.
There's also a problem I encounter a lot on SO (among other places) where I'll ask for a solution to X and end up with a bunch of suggestions to redefine my problem to solve Y instead because they don't understand X. At least ChatGPT answers the question without trying to redefine things! And know-it-alls on SO frequently downvote QUESTIONS they don't like and argue about whether they should even be asked. In fact, I find that MOST Delphi questions submitted lately all have negative upvotes ON THE QUESTION ITSELF. This just screams out, "Don't post stupid questions here!"
ChatGPT is far less judgmental in that respect, which I think is a Good Thing.
-
3
-
-
On 3/8/2021 at 7:51 AM, Attila Kovacs said:Exactly that's why we wish VCL would be threaten a bit better.
I'm sorry, but I really don't know what you're going on about. Historically speaking, Borland/Inprise/Codegear/Embt have always maintained a POV where they provide basic components and leave the door open for 3rd-parties to add fancier and more embellished components to the landscape.
The thing you're pointing at really is that the Delphi landscape has been abandoned by most 3rd-party providers. Many of them just closed their doors, and many are making components for C#/.NET instead because the market is two or three orders of magnitude larger than for Delphi components. Follow the money and you'll see where the investments are being made.
All of this needs to be taken against a backdrop where the entire industry has become far too fragmented, supporting too many different and incompatible platforms: Windows, MacOS, iOS, Android, Linux, and a bunch of smaller ones. VCL itself ONLY works in Windows while the entire world has shifted to a "mobile-first" development imperative, meaning iOS and/or Android. VCL doesn't get you there. So the MARKET has gone in a different direction entirely!
Delphi has FMX to address this, but ... IntraWeb was introduced well over a decade ago and it's still hardly being used. I played with FMX in Windows, and I didn't like it. Everywhere I worked was 100% Windows, so I saw no need to waste my time with FMX.
Microsoft creates standards mostly by buying up companies and then announcing their solution is the Next Big Thing. They do that pretty much every year or two, and as a developer who lives and breathes what Microsoft says, you'll need to keep shelling out more and more money to buy the SDK for their Next Big Thing, helping fund their ability to buy something else next year.
You also have to abandon the time you've invested learning the last umpteen platforms they bought and shoved down everybody's throats, and learn yet another one that's not compatible with any of the previous ones. And don't forget that every 5-7 years they introduce a new version of Windows that deprecates older features that cause older software to break. (Apple has been doing that a lot more lately as well, and it's very expensive to keep up with all of the software they keep breaking.)
From my catbird's seat, the future ahead is WEB APPS. And, sorry to say, neither VCL nor FMX will be useful on those shores.
Honestly, I can pound stuff out in VCL incredibly fast. But it's really at the end of its life. There are tons of companies maintaining old Delphi apps written in D7 using VCL and fancy components like DevEx grids and whatnot. They're loathe to upgrade them at all, except on the fringes and where changes in laws require them to fix some things.
Over the last decade, I can't think of anything that has been added to the Delphi language or the VCL that would add any real value to these old apps build in the D7 era. At least the newer versions of Delphi let you continue matintaining them without anything breaking, unlike most Microsoft tools that pay very little heed to backward compatibility.
Give it up! Your comments make me think if the image of the guy standing in Tianamin Square in China trying to stop a brigade of tanks.While I totally agree with your general sentiments, this isn't about the VCL or Embt -- Windows Desktop apps are simply not where companies are investing in new software development efforts, and they haven't been for years. Like I said, follow the money and you'll see where the market is heading. Windows apps ain't it.
Whether the future is being driven by mobile apps or web apps or AR/VR or AI or thought control ... NONE of that is reachable by VCL! The VCL is for WINDOWS DESKTOP APPS ONLY! And that is NEVER going to change.
The VCL the last general store on a once vibrant Route 66 that has been bypassed by a bigger, faster freeway taking people to other places.
-
6 hours ago, Sherlock said:@David Schwartz But that is exactly the point: ChatGPT just blurts out unchecked stuff someone might naively use and if it compiles ... ships it. No matter what happens then. And that is simply unacceptable and dangerous, no matter how fascinating (or in my case not) on may consider the subject.
So basically, ChatGPT and similar tools are the computer programming equivalent of Fox Entertainment Network?
It seems to work fine for Fox! It has made lots of people very rich telling lies, and the people who are lied to have no problem defending them with their lives.
Sadly, there are programmers who cannot tell the difference any more than people who can't tell that pretty much everything talked about on Fox is a lie.
This only seems to argue for better and more disciplined unit testing -- unless you're working at an organization that will throw out the tests (votes?) if they don't give the results they want.
-
5 hours ago, Stefan Glienke said:I think we are down to the real issue here: one's own personality.
I rather filter out some ego-stroking to get good peer-reviewed advice than some untested garbage but I know people that are already offended when you say: "Sorry, but there is a slight possibility of you being not 100% correct here" (actually meaning: you could not be more wrong). People with a personality like that are usually the ones complaining about SO. I am worried that their solution is using AI-provided help that is completely unchecked and will turn into the software that runs the world in the future.
I personally don't care. My experience is that most programmers tend to be fairly blunt about stuff anyway, which is how my mind works.
But what you're saying points to the Achilles heel in ChatGPT which is that it's egoless, and there's really nobody to blame. So you can cuss and fume and say whatever you want, and nobody is going to care. Over the years, people have used the Bible to support just about every side of every moral issue known to man, and there have been more people slaughtered in the name of "god" over disputes springing from the various interpretations of it than perhaps anything else in history. Nobody knows the true authors, and whomever they were they lived 2000 years ago and certainly aren't around to defend how their words are abused today! What's going to keep that from happening with material generated by AI things like ChatGPT?
I've worked with interns over the years, and on a good day they're marginally better than ChatGPT at writing code. For demos and samples, that's fine, but most of the code "isn't ready for prime time", as they say. That doesn't mean it's not instructive.
For me, the greatest value I've seen in ChatGPT so far is that it can generate code and transform it (reliably) in ways that's beyond the ability of editors and regex expressions and would otherwise require some rather expert programming to implement. Said another way, it's good at generating what I call "plumbing" code, sort of what ETL covers.
It also seems useful for getting a bunch of code that's reasonably useful for implementing an algorithm -- it may not be 100%, but it might take less time to get there than starting completely from scratch. (Of course, that's a matter of personal opinion, but it's a valid use-case.)
-
12 hours ago, omnibrain said:Supabase
Try Supabase. It is postgreSQL+postgREST+Auth.
You can manage your access rights via row level security directly in the database.
If the automatic API via postgREST does not fit you can always build something yourself later, because in the end it's postgreSQL and you can use it as such.
thanks. I'm working with TMS XData and a bit of Aurelius, and Sphinx can handle all of the auth stuff if I want to build it myself. The back-end DB is irrelevant, as Aurelius can connect to pretty much anything.
-
20 hours ago, mytbo said:You wrote a long text but probably didn't spend a second to follow my links. If you did, what are you missing? I'm happy to take suggestions for further articles.
With best regards
Thomas
You said:
On 3/14/2023 at 10:20 AM, mytbo said:If you want to use mORMot for the implementation ...
I do not. I'm looking for basic principles that rise above implementation issues. I didn't find anything there that was relevant to what I'm looking for, but I appreciate that they seem to ring a bell for you.
-
Y'all seem to have missed the point -- this is what people are using StackOverflow for most of the time, and most of that code isn't any better than what ChatGPT produces.
The biggest difference is there are a bunch of smartypants mods on SO who are constantly flagging crappy code, correcting obvious errors, and making tons of commentary about the code, the poster, and each other's comments.
It's interesting how this thread looks so similar to a typical SO post.
-
The problem isn't the source of the information. It's how the information is being used and framed / portrayed.
Anybody who has been following what's going on with the defamation suits from Dominion and Smartmatic against Fox, their management team, and their on-air lying sacks of sh*t, can see how the people running Fox are clearly targeting viewers who have such flawed critical thinking skills that they'll fall for anything the talking heads on Fox say as long as it fits a particular pattern of communication or point of view.
I have a friend who's retired, and all he watches on TV is Fox. I called him to ask if he'd make me a small loan for a few days and he said "sure, but I need to get cash." I said, "Why? What's wrong with Zelle?" He said, "Haven't you heard? The IRS is coming after anybody who uses payment things like Zelle for sending more than $600 to ANYBODY! I don't want to deal with the IRS over a stupid loan like this!" I thought, "Oh, boy, I guess this is the latest crock of BS that Fox is scaring people about this week..." He's on Social Security and doesn't even file a tax return because he doesn't earn enough, and yet he's worried about getting audited by the IRS because of nonsense Fox is blathering on about this week to make Biden look bad. It's pretty hard to deal with people who can't even break down the most simple things they hear or read in the media as they may or may not apply to them!
Now we've got ChatGPT that is, in all likelihood, far more accurate and less biased than Fox, and yet people are up in arms over the mistakes it seems to be making. Sure, I've found several. But Dominion and Smartmatic are very likely to get default judgments against Fox to the tune of nearly $4 billion for the mountain of evidence their lawsuit discovery processes have shown that Fox exec and talking heads have engaged in a steady practice of telling lies to their viewers in order to boost their ratings and profits. Period. And the people who make the most noise about ChatGPTs errors probably don't even realize Fox is FAR less reliable and truthful -- nor will they even accept that as a possibility.
There was a book published in 1976 by Joseph Wesienbaum called "Computer Power and Human Reason". He was the founder of MIT's AI Lab. At one point in the book, he said he was asked by a reporter something like this: "What is it that humans can do that judges, psychologists, and other experts can do that computers cannot do?" His response was, "the question is what we as humans should allow or not allow computers to do that humans do."
I have not found that particular quote, but here are some others I found onilne:
https://www.goodreads.com/author/quotes/496834.Joseph_Weizenbaum
-
2
-
-
Ya know ... it's easy to dismiss things that it does as mistakes or just stuff it makes up, but to me they represent inferences that point to other things to look into. This is actually something I can personally relate to, as a lot of things I say get dismissed as nonsense. A lot of them turn out to be pretty damned accurate later on... I chalk this up to Asperger's. Not sure if it's a blessing or a curse.
Anyway I asked ChatGPT to show the code for that non-existent TListDataSet and ... if you've got a paid account, it might generate an entire unit. With the free account, it kept quitting about half-way through the code.
-
7 minutes ago, Kryvich said:@David Schwartz
The chain TList -> TClientDataSet -> TListDataSet is too long. It would be enough TList -> TClientDataSet. The client dataset is a dataset, so the problem is solved.honestly, not having seen or heard of this TListDataSet, I couldn't really tell what it was doing there.
TDataSets have a specific interface, much of which is navigational in nature. TLists have some navigation, and the nature of CRUD operations are different. So you'd need an adapter to make them behave more like TDataSets.The one component I'm familiar with is more direct.
-
4 minutes ago, Kryvich said:Even if this TListDataSet existed, I do not think that the proposed approach is optimal.
in what respect? I mean ... what kind of use-case are you thinking of?
I asked about this because I've got a bunch of JSON data (array of records) that I'm stuffing into objects added to a TList, and it seems the only way to get something I need is to use a DB-aware control to view them. So I need to get them into a dataset so they can be viewed. Then the whole thing gets thrown away.
So the choice is to go from JSON --> TDataSet or TList<T> --> TDataSet, both of which are dependent on the same issues:
How much time do you want to spend writing code that speeds this up by less than a second?
It's a little funny to me that all of this great technology we have at our fingertips is all rooted in stuff designed back in the 90's to support Client/Server database technology while today a large amount of our work centers around data shipped between servers as JSON packets, that's either parsed and used immediately or stuffed into classes, and is mostly transient and never intended to be put into any kind of structured DB.
There are even plenty of NO-SQL DBs available today to help manage this data.
Yet the most useful visual components are all driven off of TDataSets that are intended to be connected to databases.
DevEx grids are incredible, but last I saw, they're totally driven off of TDataSets and are useless for JSON data and lists of objects.
-
1
-
-
2 minutes ago, Stefan Glienke said:Because there isn't (at least not in the RTL) - ChatGPT is making that up (as so often).
HEHE ... I do know of something similar.
I did ask this:
Where is TListDataSet found?
TListDataSet
is part of theData.DB
unit in Delphi. It should be available in all recent versions of Delphi.Note that
TListDataSet
is not a visual component, so you won't find it in the component palette. You'll need to create it in code, like this:uses Data.DB; var MyListDataSet: TListDataSet; begin MyListDataSet := TListDataSet.Create(nil); try // Use the TListDataSet here... finally MyListDataSet.Free; end; end;
Once you've created the
TListDataSet
, you can use it like a regularTDataSet
.-----------------------------------------------------------------
It seems to know a lot about something that doesn't exist. It makes me wonder how much proprietary / restricted / unpublished data this thing was trained with.
-
I've been asking ChatGPT (free version) lots of questions about Delphi and things that a lot of devs would have trouble answering, and I'm quite amazed at the responses I've been getting. I think StackOverflow has met its match! It even does a decent job of explaining what the code is doing.
Here's one I thought I'd share.
--------------------------------------------------
In Delphi, is there any kind of an adapter or class that takes a TList<T> and makes it look like a TDataSet?
[I had no idea there was such a thing as TListDataSet component in Delphi!]
Yes, you can use a TListDataSet component in Delphi to make a TList<T> look like a TDataSet.
Here's an example:
uses System.Classes, Data.DB, Datasnap.DBClient; type TMyData = class // Define the fields in your class FField1: string; FField2: Integer; FField3: TDateTime; // Add more fields as needed end; var MyList: TList<TMyData>; MyDataSet: TClientDataSet; MyListDataSet: TListDataSet; begin // Assume MyList is already populated with data MyDataSet := TClientDataSet.Create(nil); try // Define the fields in the TClientDataSet MyDataSet.FieldDefs.Add('Field1', ftString, 50); MyDataSet.FieldDefs.Add('Field2', ftInteger); MyDataSet.FieldDefs.Add('Field3', ftDateTime); // Add more fields as needed MyDataSet.CreateDataSet; // Iterate through the TList<T> and add each item to the TClientDataSet for MyData in MyList do begin MyDataSet.Append; MyDataSet.FieldByName('Field1').AsString := MyData.FField1; MyDataSet.FieldByName('Field2').AsInteger := MyData.FField2; MyDataSet.FieldByName('Field3').AsDateTime := MyData.FField3; // Set more fields as needed MyDataSet.Post; end; // Create a TListDataSet and set it's DataSet property to the TClientDataSet MyListDataSet := TListDataSet.Create(nil); MyListDataSet.DataSet := MyDataSet; // Now you can use the TListDataSet like a regular TDataSet MyListDataSet.First; while not MyListDataSet.Eof do begin // Do something with the data MyListDataSet.Next; end; finally MyListDataSet.Free; MyDataSet.Free; end; end;
In this example, we create a TClientDataSet and define the fields in the dataset to match the fields in TMyData. We then iterate through the TList<T> and add each item to the TClientDataSet. Finally, we create a TListDataSet and set its DataSet property to the TClientDataSet, allowing us to use the TListDataSet like a regular TDataSet.
Note that if your TMyData class uses properties instead of fields, you'll need to use the FieldByName method to set the field values in the TClientDataSet, like this:
MyDataSet.FieldByName('Field1').AsString := MyData.Field1; MyDataSet.FieldByName('Field2').AsInteger := MyData.Field2; MyDataSet.FieldByName('Field3').AsDateTime := MyData.Field3; // Set more fields as needed
How can the fields be defined by using RTTI on the type of object in the list?
You can use Delphi's RTTI (Run Time Type Information) to automatically define the fields in a
TClientDataSet
based on the fields in your class. Here's an example:uses System.Classes, System.Rtti, Data.DB, Datasnap.DBClient; type TMyData = class private FField1: string; FField2: Integer; FField3: TDateTime; public property Field1: string read FField1 write FField1; property Field2: Integer read FField2 write FField2; property Field3: TDateTime read FField3 write FField3; end; var MyList: TList<TMyData>; MyDataSet: TClientDataSet; MyListDataSet: TListDataSet; MyCtx: TRttiContext; MyType: TRttiType; MyProp: TRttiProperty; MyFieldDef: TFieldDef; begin // Assume MyList is already populated with data MyDataSet := TClientDataSet.Create(nil); try // Use RTTI to define the fields in the TClientDataSet MyCtx := TRttiContext.Create; try MyType := MyCtx.GetType(TypeInfo(TMyData)); for MyProp in MyType.GetProperties do begin MyFieldDef := MyDataSet.FieldDefs.AddFieldDef; MyFieldDef.Name := MyProp.Name; MyFieldDef.DataType := MyProp.PropertyType.HandleToFldType; end; finally MyCtx.Free; end; MyDataSet.CreateDataSet; // Iterate through the TList<T> and add each item to the TClientDataSet for MyData in MyList do begin MyDataSet.Append; // Use RTTI to set the field values in the TClientDataSet MyCtx := TRttiContext.Create; try MyType := MyCtx.GetType(TypeInfo(TMyData)); for MyProp in MyType.GetProperties do begin MyFieldDef := MyDataSet.FieldDefs.Find(MyProp.Name); if Assigned(MyFieldDef) then begin MyDataSet.FieldByName(MyFieldDef.Name).Value := MyProp.GetValue(MyData).AsVariant; end; end; finally MyCtx.Free; end; MyDataSet.Post; end; // Create a TListDataSet and set it's DataSet property to the TClientDataSet MyListDataSet := TListDataSet.Create(nil); MyListDataSet.DataSet := MyDataSet; // Now you can use the TListDataSet like a regular TDataSet MyListDataSet.First; while not MyListDataSet.Eof do begin // Do something with the data MyListDataSet.Next; end; finally MyListDataSet.Free; MyDataSet.Free; end; end;
In this example, we use TRttiContext and TRttiType to iterate through the properties of TMyData and define the corresponding fields in the TClientDataSet. We then use TRttiContext and TRttiProperty to iterate through the properties of each item in the TList<T> and set the corresponding field values in the TClientDataSet.
Note that this example assumes that the properties in TMyData have the same names as ...
It choked at this point, but the answer is fairly complete.
Curiously, I ran it again to get it un-stuck, and this time it came up with a slightly different take on defining the fields:
MyDataSet := TClientDataSet.Create(nil); try // Use RTTI to define the fields in the TClientDataSet based on the properties of TMyData Ctx := TRttiContext.Create; try Typ := Ctx.GetType(TMyData); for Prop in Typ.GetProperties do begin FieldDef := MyDataSet.FieldDefs.AddFieldDef; FieldDef.Name := Prop.Name; case Prop.PropertyType.TypeKind of tkString, tkLString, tkWString, tkUString: FieldDef.DataType := ftString; tkInteger, tkInt64: FieldDef.DataType := ftInteger; tkFloat: FieldDef.DataType := ftFloat; tkEnumeration: FieldDef.DataType := ftBoolean; tkVariant: FieldDef.DataType := ftVariant; tkClass: if Prop.PropertyType.AsInstance.MetaclassType = TDateTime then FieldDef.DataType := ftDateTime; // Add support for more property types as needed end; end; finally Ctx.Free; end; MyDataSet.CreateDataSet;
-
Have you considered using an external store accessed via a URI? That would have the advantage of users being able to move from one device to another and have their data follow them.
If you read the tea leaves, vendors are making things harder and harder to create mobile apps that follow a usage model similar to traditional desktop apps. That's forcing the data to be saved remotely. That does make it challenging to operate without internet access. But internet access is becoming pretty much ubiquitious these days, esp. for low-security needs. Just encrypt the data and save it as a blog somewhere and manage it via an in-memory DB. (Probably needs versioning and other stuff to prevent corruption, but that shouldn't be too difficult.)
-
5 minutes ago, KenR said:I have also struggled with this concept. I am currently using TMS Web Core with the db server created by using TMS XData. For most visual components I am using DevExtreme. This seems to work very well. The main advice I can give is to retrieve the absolute minimum amont of data with each request.
I'm also working with Web Core. My needs are actually quite simple right now -- I need to be able to store stuff that might otherwise go into an INI file for saving user state data. A web app requires that data to be saved in a single, remotely-accessible place, because the user can run the web app from any device anywhere, and that data needs to follow them around. The ideal place would be wherever the rest of the user profile data is being stored. But I can't find anybody that provides user / member management that lets you add your own fields or even a single blob to save stuff that's invisible to their UI.
I've been looking at TMS Sphinx, but it's like having to completely reinvent the wheel. Right now I'm building an MVP and I want something as turn-key as possible. The most common suggestion I've been getting is to use Wordpress. Ugh. No thanks! Even the Memberful folks suggested that.
So far, there are solutions I've found on one end that offer member management that have REST APIs but cannot be used to save a few additional user-specific data items that aren't visible to users; and on the other end there are platforms that let me save whatever I want (they're a general DB) but I'd need to build all of the member management, auth, payment processing, and security stuff into it.
There's even AirTable, which is quite comprehensive, but it started out life as an easy-to-use drag-n-drop GUI-based web DB tool, and the REST API was added as an afterthought. Everything in the DB has to be added from the UI side and it doesn't look well-suited for saving user-specific state data from a middle-tier service.
-
13 hours ago, Lars Fosdal said:My hard-earned advice
- Refrain from replicating the database structures in the REST API. Think about the tasks you want to execute, and what data that is needed for these tasks. It doesn't matter how they actually are stored in the database, as it is the REST server's job to sort out what goes where and how. It also enables you to swap out the underlying database without changing the API itself.
- Use JSON data packages. The good thing about these, is that you can have missing or extra fields in both directions, making the API less fragile. If a value is missing and not critical, simply use a default instead. If an unknown value arrives, just ignore it. This moves the versioning to the API levels, instead of purely on the database.
- Try https://api.swaggerhub.com for building APIs. Swagger files, now known as OpenAPI definitions, are very useful as there are numerous dev tools that can use them to create both server -and client-side code or configuration.
-
Do not expose primary keys in the APIs - if you need an actual unique key, create a GUID field in the database and use that as the unique id.
It is way too easy to do serial breach attempts on queries where the PK is just an integer. - Use secure connections - i.e. https.
-
Make sure you use proper authentication. OAuth2 with limited time keys.
-
Remember why it is called RESTful and obey the rules
All great points. To me, I'm looking for what amounts to an embedded DB with a REST API to handle security issues better than you get by just using a raw IP:port# protocol, which is what pretty much every DB server in the world does. They all have UIs of various types, but none of them are tightly coupled the way I've found in my search for a solution. The vendors seem to start with a nice web-based UI drag-n-drop designer and then slap a REST API onto the side to make it accessible by code. But they ALL are tightly coupled to their doggone UI. WTF? MySQL has no UI -- but there are plenty of tools that let you connect to it and manage it via a nice UI, the most common and well-known of which is probably phpMyAdmin. But look how many fancy UI-based tools exist that let you connect to any number of DBs that don't rely or depend on any UI parts of those DBs that might exist. The market for them exploded in the 90's because of Y2K and it's still quite healthy -- only now this tech is referred to as "ETL" support.
So why is REST support for DBs always viewed as an "add-on"? And why is it mostly just half-assed in terms of what it supports?
That 3rd one in particular about swagger is an especially great point, but I can't figure out why so few vendors actively embrace it. It's not unlike SOAP, and SOAP requires a special compiler to take the WSDL specs and generate an interface unit for it in your language du jour. Swagger 3.0 is complete enough that there should be tools that read the swagger file and generate an interface unit for it in whatever language you want. They even have a list on their site with tools for a few dozen different languages, but ... Delphi ain't one of them. Hello EMBT? Don't you think Delphi is a useful enough platform for building REST interfaces to warrant vendor-sponsored support for a swagger tool? (TMS' Wagner Landgraf built something last year that's posted on github as open source, but they're just a 3rd-party tool vendor.
I'm still pretty new to REST stuff, but from where I stand, I've come to two conclusions:
-
TObject and/or RTTI should support toJSON and fromJSON in the same way that they support the abliity to read and write DFM files to serialize and deserialize objects, and it should not be done in a way that's VCL-specific
- You should be able to point to a swagger spec using something that's shipped "in the box" and have it create a robust class definition from it that can ingest data from that API and return PODOs, even if it's all just a bunch of Variant fields to handle ambiguous field definitions
There are at least a half dozen tools in the C# / .NET world that do the latter. I only know of one for Delphi (Wagner's).
I see this as a necessary part of the support needed to work with embedded REST-based DBs, but not sufficient. The authentication and security part is also necessary, but completely unrelated -- how to you read a swagger spec and generate a fully-compliant auth layer? Is it even possible? At least SOAP -- as ugly and inefficient as it may be -- has a standardized security protocol you can implement (AFAIK).
IsNullOrWhiteSpace???
in General Help
Posted
You probably don't need the class name in front.
and isn't this form also acceptable: myString.IsNullOrWhiteSpace