How can I get a dataset of in-memory objects? - delphi

Does anyone know of a TDataset descendant that works with Generics and RTTI, so that I can write code like this, and make use of data-aware components in the GUI? :
...
ds:TDataset<TPerson>;
...
procedure DoStuff;
begin
ds:=TDataset<TPerson>.create;
ds.add(TPerson.Create('A.','Hitler',77));
ds.add(TPerson.Create('O.','Bin Laden',88));
end;
This should be possible. The fielddefs can be created via RTTI because the exact type of the data is known. Values can also be automatically marshalled back and forth, so you can both view and edit data that's in a class or a record.
I hate having to write a lot of useless marshalling code, while the required information for that is available via RTTI already.
Or maybe somebody once wrote some sort of TEnumerable <-> TDataset adapter?
Does something like that exist, or should I start writing one?
...
The closest thing that I could find is an (excellent!) example by Marco Cantu, from Mastering Delphi 7, but the code itself doesn't make use of new language features like generics, the new RTTI system, or attributes, and it doesn't work with Unicode delphi. TDataset has changed since D7 too.

The TAureliusDataSet included in TMS Aurelius comes very close to that.

Take a look at EverClassy Dataset from Inovativa at www.inovativa.com.br/public.

another one is Snap Object Dataset http://digilander.libero.it/snapobject/

DotNet4Delphi by A-Dato Scheduling Technology from the Netherlands is good for you.
Quotes:
From Torry's Delphi
Hook up any collection to your data aware controls.
DotNet4Delphi implements many .Net collection classes, including
generic types like List<> and Dictionary<>. Different from their
Delphi counterpart is that our generic collections also implement the
non-generic interfaces (IList, IDictionary) allowing you to access
your collections in multiple ways. This opens the door to use any
collection as a data source for data aware controls which is exactly
what the (also included) TListDataset component provides.
It targets Delphi XE and XE2.
It's an open source initiative, Delphi rocks !!!

I have found a more relevant resource and can't help sharing it! So relevant that I think it deserves a separate post rather than a mere update in my first answer.
The Dduce library for Delphi XE2-XE6 makes use of TListDataSet<...> a generic dataset component that can be used to expose a generic list as a TDataSet.
The most relevant units pertaining to the implementation of the generic dataset are:
DDuce.Components.VirtualDataSet.pas (The original SO post is itself cited by the author within the source code as a reference among others!!!)
DDuce.Components.ListDataSet.pas
Class hierarchy:
TDataSet <= TCustomVirtualDataset <= TListDataset <= TListDataset<T>
Yes, it inherits lots of features... my only wish is to have at my disposal a version working with a lessen requirement (Delphi XE without most of the other bells and whistles).
Look and feel:

Related

Efficiently access either of two Delphi datamodules with same dataobject names

I have an ugly situation where I need two datamodules (TDMA, TDMB) in a Delphi app. Each datamodule has the same data object names (queries, tables, etc.) but from a different component set (TZQuery, TADOQuery). I need this because I want to support multiple databases but not all databases are supported by my component suite. Which datamodule I need to access is determined by the DBFlag boolean variable. Besides having separate nearly identical code segments for each data access, is there some more efficient way?
If I could set a global datamodule variable like DMG to either DMA or DMB based on DBFlag then my code could reference DMG instead of DMA or DMB. That would be ideal and require very little code modifications but impossible as far as I know.
My suggestion is to drop building your DataModules based on specific datasets. Build them using only TClientDataSet and write all your code or link all your DataSources to these datasets. Then create other DataModules to hold your specific datasets and use your selection method to choose which one to respond as a data provider for the CDS instances. The idea of using an interface to do that is indeed a good one.
This approach will remove all you duplicate code and you will separate business logic (the code that handles the data inside the CDSs) from persistence (the code that transfers data rows from and to the data server).
It's perfectly possible to have a global variable or, better, a function or singleton
class or perhaps best of all, an interface, which returns a reference to an abstraction
of what dmA and dmB have in common depending on a boolean flag. Exactly how to do it,
though, would benefit from some careful thought, most of which you will need to
do yourself because only you know the details of your project and its requirements.
However, there are a few potential issues with it that I think are likely to lead you
towards an implementation like one now-deleted comment suggested, that does away with
datamodules (or hides them away) and uses custom DB objects or interfaces instead to
provide consumer access from forms, reports, etc.
One big issue is to do with the way object visibility works in Delphi + its IDE.
Consider a project which has a unit MyForm1u which is to be a consumer of your DB objects.
and units dmAu and dmBu which contain DB components that you've added via the IDE designer,
that may have the same names in both units but can be of different instance types.
Now, MyForm1u can certainly use dmAu and dmBu, but that has the problem that the DB components
in dmA and dmB are necessarily of published visibility (because that's what needs to
be the case for them to be streamable and IDE-designable). So, although you could have a function which returns (an instance of) dmA or dmB, if MyForm1u Uses dmAu and dmBu, there's nothing enforce
encapsulation of them so that access to them goes only via that function.
What you could do is to define a common ancestor datamodule, call it dmCA in unit
dmCAu and then descend dmA and dmB from it - this would be a bit fiddly to do after the fact
because if dmA and dmB already exist, you would need to hand-edit their DFM files
to adjust component ancestry if you wanted to have some components on dmCA instead. But
starting anew, you could easily create a new dmCA in your project, containing any DB
components in common between dmA and dmB which are of the same instance type, and then descend dmA and dmB from it in the IDE.
This would give you a project structure in which myFormu1 doesn't Use dmAu or dmBu
directly nor, some would say, dmCA. A better approach might be to have it Use none
of them but rather a unit X which contains a function returning some class, or better
interface, which in turn has a group of functions which return references to the
components of dmA and dmB that they have in common in term of name (actually the important thing is their function within the data model of the datamodule) and ancestral type, e.g.
function MyDataSet1 : TDataSet;
so that it can return the AdoQuery1 of dmA or the SqlQuery1 of dmB, depending on
your boolean flag.
Provided your consumer unit(s) Use only unit X and not dmAu, dmBu or dmCAu, that will
enforce the encapsulation of their contents.
This class- or interface-based approach would preclude "wiring up" consumer objects
like TmyForm1 to DB objects using the usual point 'n click approach courtesy of the
IDE's Object Inspector, but these days many would say that that would be no bad thing.

Delphi extending class

first of all, sorry if the title is a bit confusing.
i'm planning to develop a small erp application. this apllication will use plugins/addons. this addon might add or extend some modules of the base application.
for example, i have TCustomer class with property "id", and "name".
addon 1 will add a property "dateofbirth".
addon 2 will add a property "balance" and a method "GetBalance".
addon 1 and addon 2 are not aware of each other. addon 1 might be installed and not addon 2 or vice versa. so both addons must inherit the base tcustomer class.
the problem is when both addon are installed. how do i get extended properties in both addons? i will also have to extend the form to add controls to show the new properties.
can it be done using delphi? what is the best way to achieve this? maybe you can point me to some articles of examples?
thanks and sorry for my poor english
Reynaldi
Well, as you are already aware, you can't have more than one plug-in extend an existing class by inheritance. It would confuse the heck out of any app, including any programmer's dealing with the code.
What you need is some type of register mechanism in your TCustomer class where every plugin can register its specific properties, or provide a couple of call back functions for when a TCustomer instance is created (initialized), loaded, stored, or deleted. The core TCustomer after all really doesn't need to know more about the plug-in's than the fact that they might exist.
Depending on how you intend to load/store your data, the core TCustomer class doesn't even have to be aware of the extensions. It would be quite sufficient to make the persistence mechanism aware of plug-ins and provide a way for them to register a call back function to be called whenever a TCustomer / TOrder / TWhatever is initialized / loaded / saved / deleted.
You will also have to make the GUI aware of the plugins and provide the means for them to register pieces of UI to have the main GUI create an extra tab or some such for each plug-in's specific controls.
Sorry no code example. Haven't yet implemented this myself, though I thought about the design and it is on my list of things to play around with.
That said, to give you an idea, the basic mechanism could look something like this:
TBaseObject = class; // forward declaration
// Class that each plug-in's extensions of core classes needs to inherit from.
TExtension = class(TObject)
public
procedure Initialize(aInstance: TBaseObject);
procedure Load(aInstance: TBaseObject);
procedure Store(aInstance: TBaseObject);
procedure Delete(aInstance: TBaseObject);
end;
// Base class for all domain classes
TBaseObject = class(TObject)
private
MyExtensions: TList<TExtension>;
public
procedure RegisterExtension(const aExtension: TExtension);
procedure Store;
end;
procedure TBaseObject.RegisterExtension(const aExtension: TExtension);
begin
MyExtensions.Add(aExtension);
end;
procedure TBaseObject.Store;
var
Extension: TExtension;
begin
// Normal store code for the core properties of a class.
InternalStore;
// Give each extension the opportunity to store their specific properties.
for Extension in MyExtensions do
Extension.Store(Self);
end;
Such an "evolving" class is some kind of multi-inheritance.
I think you shall better use interfaces instead of classes.
That is, each plug-in will serve a class implementation, but you will work with interfaces, and an interface factory.
See this article about "why we need interfaces", or this article from our blog about interfaces and a comparison with classes.
You can test if a class implements an interface: for a plug-in system like yours, this is probably the best way to implement an open implementation. Duck typing is very suitable for plug-ins. The whole Delphi IDE (and Windows itself) is using interfaces for its plug-in systems (via COM for Windows). For a less strong implementation pattern, you can use not interfaces, but late bindings: see the answer of this SO question.
Take a look at the SOLID principles, especially the single responsibility principle. Your question directly breaks this principle: you attempt to mix client personal information (like name) and accounting (like a balance). If your project grows up, you'll probable be stuck by such a design.

Interfaces in Lazarus/FPC: Multiple inheritance

I'm trying to create a shell extension to provide EXIF information for JPEG files in Windows Explorer "infotips", and am using Lazarus as this needs to produce an x64 DLL.
Does Lazarus support multiple inheritance with interfaces, and if so, how do I go about it?
for example, something like:
type
IInfoTips = interface(IPersistFile, IQueryInfo)
Thanks,
Mark
No, interfaces in FPC does not support multi-inheritance yet.
What you can do is letting the implementation class inherit from both interfaces:
type
TMyInfoTips = class(TInterfacedObject, IPersistFile, IQueryInfo)
But not at interface level, as you wish. Such statements won't compile:
type
IInfoTips = interface(IPersistFile, IQueryInfo)
You can only "inherit" from a single interface type.
Delphi does not support it either. Only the defunct Delphi for .Net compiler did... but because .Net/C# IR supports (and expects) the feature.
I'm also missing this feature in Delphi or FPC.
Both interfaces are defined in shlobj for Free Pascal/Lazarus, just like on Delphi. If symbols changed units during the Delphi lifetime, we try to put them in the more recent units, but there is a large backlog there.
All this should be largely Delphi compatible, maybe it is easier if you explained what exactly doesn't work like expected.
Added after Arnaud's comments:
No it does not. Objects implement interfaces in Pascal. I don't really understand why it is really important to do this anyway. Sure it is a bit of syntactic sugar, but since any delphi style interface implements Iunknown, you can just query an interface for another interface:
uses activex;
var x :IPersistfile;
y :IPersistStream;
begin
x.queryinterface(IID_IPersistStream,y);
end.

Setting Unit Defaults?

Not a programming question as such, but..
..Is there a way from the Delphi IDE to define information that will be applied to newly created Units?
For example, suppose I wanted each new Unit to add some commented information to the top, like so:
I like to add such information to Units so that anyone else who may need access to it has some brief information. Obviously I am not expecting the IDE to fill in the Overview information.
I noticed some OpenSource Components include the License Information at the top of Units, I assume they were just Copy and Pasted in there, but wouldnt it be handy if there was a way to Automate such IDE behaviour?
Additionally, I have a few external Units added to my Library Path, which I add to the Uses Clause of a Form/Unit when needed. There is one paticular Unit I always find myself using, It would also be handy to Automatically include X Unit to the Uses Clause of New Units.
Is there a trick to doing something like this, or should Copy and Paste be enough?
Thanks.
You can consider using a Delphi live template too.
The closest you can get is to use GExperts or CNPack. These are great IDE enhancements and they can be used to paste configurable pieces of code using a simple hotkey. In GExperts this is called Code Librarian, CNPack has a similar feature. They contain a lot of other valuable tools so it might be worth to check these out.
Like Marjan already mentioned using an expert for a new custom unit, you can also make an IDE expert rewriting Delphi's default unit code for maximum customizability. But since this answer likely implies the most required work of all, I shall not go in detail or sample code. It's just a possibility.
You'll have to stick to copy/paste. If there was a slick way to do this then every single Delphi programmer on the planet would have used it to turn this
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
into this
type
TForm1 = class(TForm)
end;

How do I determine the type of the implementing object of an interface

I'm attempting to write a unit test for a simple factory class that creates one of several possible implementing objects and returns it as an interface reference.
DUnit has a built in procedure, CheckIs(AObject: TObject; AClass: TClass; msg: string), that based on its name and the parameters it accepts should fail the test if the object's class type doesn't match the expected one. The only problem is it requires an object reference not an interface reference.
So I'm trying to use CheckTrue and perform the comparison in the body of the test but I'm not as familiar with Delphi's type checking support as I am with C#'s.
I know the is operator is out of the question since it only works with object references.
CheckTrue(LMyInterfaceReference {comparison here} TMyClass);
Any suggestions?
BTW, I'm using Delphi 2009 so I don't have access to the new RTTI support added in 2010+.
I'm wondering why you MUST have to test this... maybe you really don't have to.
But if knowing the underlying object of a Interface is a must, you have two choices:
Add a method to the interface which returns the underlying object, just a TObject, and implement this in each class just by returning self.
Hack a bit, for example using this Interface to object routine.
If you don't like hacks and don't feel like upgrading to Delphi 2010+ you may use an interface like this:
IImplementingObjectInterface = interface
function GetImplementingObject: TObject;
end;
Make sure your objects also implement this interface and use it to extract the implementing object. If you need to do this for a lot of objects you can define your own TInterfacedObject derivate that already implements this so you can simply change your inheritance and be done.
Barry Kelly (one of the main Embarcadero Delphi Compiler Engineers) wrote a nice An ugly alternative to interface to object casting this week.
It answers your question.
The fun is that Hallvard Vassbotn wrote a very similar piece of code back in 2004.
From Delphi 2010 on, you can just use an is check or as cast to go back from interface references to object references.
--jeroen

Resources