Page 1 of 2

Multiple master datasets in master-detail relationships

Posted: 06.01.2007, 14:08
by zsoca
Your ZeosLib DBO Version: 6.1.5
The IDE you are using: Delphi
Version (and maybe patchlevel) of the IDE: 7
The database you are using: Firebird
Version of the database: 1.5
Used protocol: TCP/IP
[hr]Error description and post

Hi friends!

I have been using ZeosLib for more than two years now, and I am very satisfied. I was following your work, and now I feel I can contribute too.
I got to a point, where I need more master datesets for a client dataset, and I face the problem, that this issue is not solved yet...
Here is my idea:
We introduce a new property DataSources, which is mutually exclusive with DataSource. In DataSources we list the master datasources. The problem that arises is, that if there are more fields with identical names among the master datasets, which one to select as the source for the parameter with that name? This could be also easily solved by a visual property editor that would store the bound pairs (parameter <-> datasource.fieldname) in a new property.

My question is: are you interested in such a feature, and would you like to include it into ZeosLib?
I am awaitnig your comments and improvements!

Best regards, Zsolt Balanyi

Posted: 07.01.2007, 15:09
by mdaems
Hi Zsolt,
Very happy to hear you want to contribute.

I only don't understand how a client dataset can have multiple master data sets? Can youexplain a little more the relation between the client and his masters?
Maybe best using an example to make it more clear.

Mark

Posted: 08.01.2007, 13:23
by gto
Wow, sounds.. ahm, confusing ! :D

You'll need to check for same field names between datasets and sync at every update from all linked datasets.. It may be interesting, if you will use it ;)
I'll keep with Mark, an example will be good!

Posted: 08.01.2007, 20:05
by zsoca
Hi friends!

Ok, here's an example:
two master tables:
LAYER(LAYERID, DESCRIPTION, .....)
AREA(AREAID, DESCRIPTION, .......)
detail table:
OBJECTS(OBJID, LAYERID, AREAID, DESCRIPTION, ....)

There are multiple layers on the map, and there are some areas on them. We might want to have a dataset that contains only the objects from OBJECTS that lay on the selected layer and area. Then multiple masters have sense.
We can of course do a single (normal) master - detail using only LAYER, and then filtering always on AREAID if the cursor in AREA moves, but that is not elegant...
I hope you got the point, if still not I will post a longer explanation.

The main problem is of course the multiple field name confusion problem, but for that I also suggested a solution:
a map, where the following pairs are stored: (TParameter, TField)
A visual editor could be built that offers the parameters on one side and datasets/fields on the other.
The other functionalities would remain as in normal master-detail relationships.

Best regards, Zsolt Balanyi

join?

Posted: 25.01.2007, 08:10
by aXon_
won't a single SELECT with a WHERE clause do that? anyway, correct me if i'm wrong, i'm new to programming.

Posted: 27.01.2007, 21:33
by zsoca
Hi!

Yeap, you got the problem, but the solution is what we are talking about
Let's consider the following query:
SELECT * FROM OBJECTS WHERE
LAYERID = :LAYERID AND AREAID = :AREAID

now, how would you solve this query to follow both the actual layer and area?

best regards, Zsolt Balanyi

Posted: 28.01.2007, 23:35
by mdaems
Some thought...

Maybe you should not implement it as a new extra to a TZQuery but as a new component (eventually descending from TZQuery). Problem with adding it to the query component is needless complexity for 95 % of cases.
I'm not a real expert on how to do it but the new component should not have a 'datasource' property, only 'datasources'. But doesn't that make inheriting from TZQuery difficult?

Mark

Posted: 29.01.2007, 17:59
by zsoca
Hi folks!

Well, on the problem of the properties there is a simple solution, namely we can use them mutually exclusive. If one is set, the other is deleted. So simple.

Zsolt

Posted: 30.01.2007, 10:11
by mdaems
Zsolt,

I understand that but if we create a new ZQuery-like class, descending from AbstractDataset which hides the 'normal' fields this would make clear what each component is about. And as I just saw, it's the components that publish the properties themselves. The more : that way you don't have to clear the mutually exclusive fields as the components do not provide an interface.

Have you already looked at the impact the changes would have on the existing TAbstract(RO)Dataset coding?
Would it be possible to start coding it with IFDEF-ed logic? That way users can turn off the functionallity as long as it is in an alpha status.

Mark

Posted: 30.01.2007, 13:27
by zsoca
Hi friends!

Well, you convinced me, I will first create a totally new class, so that there will be no confusion. If folks will like it, there is still a possibility to combine the functionalities into the existing classes.

I will send you in a few days a demo if everything goes fine, depending on the load in my company.

Regards, Zsolt

Posted: 30.01.2007, 16:29
by mdaems
Reason to combine if both classes depend on the same (Abstract) basic classes?

Mark

Posted: 30.01.2007, 16:56
by zsoca
Hi!

After thinking a bit on the design, it really doesn't make any sense to combine the two approaches, as the multiple masters approach CONTAINS the services offered by the single master approach, so a single new class will do the job just fine.

The combination was a kind of idea for supporting legacy apps, where on some places would be handy to use the new feature without replacing existing components.

But, let's see the things working first, and discussing this when it works! :-)

regards, Zsolt

Posted: 02.02.2007, 17:49
by zsoca
Hello friends!

A first version is ready. Where and how should I upload it?
I belive it should use a bit more fancy mechanism for setting parameter values, but the basic idea works fine. Maybe somebody more experienced could guide me to the right solution.

TZMultiMasterQuery = class(TZAbstractDataset)
private
{ Private declarations }
protected
{ Protected declarations }
ParamLinkPairs: TStringList;
procedure ParamLinkDataChange(Sender: TObject);
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
function AddParamField(PName: String; DataSource: TDataSource; FName: String): boolean;
procedure RemoveParamField(PName: String);
function FieldOfParam(PName: String): TField;
destructor Destroy; override;
published
{ Published declarations }
property Active;
......
property Options;
end;

and the two importand methods:

function TZMultiMasterQuery.AddParamField(PName: String; DataSource: TDataSource; FName: String): boolean;
var
Param: TParam;
ParamFieldLink: TFieldDataLink;
ParamField: TField;
begin
Result := False;
if (Params = nil) or (DataSource = nil) or (FName = '') then Exit;
try
ParamField := DataSource.DataSet.FieldByName(FName);
except
Exit;
end;
Param := Params.FindParam(PName);
if Param = nil then Exit;
// if Param.DataType <> ParamField.DataType then Exit;
ParamFieldLink := TFieldDataLink.Create;
ParamFieldLink.DataSource := DataSource;
ParamFieldLink.FieldName := FName;
ParamLinkPairs.AddObject(PName, ParamFieldLink);
ParamFieldLink.OnDataChange := ParamLinkDataChange;
ParamLinkDataChange(ParamFieldLink);
Result := True;
end;

procedure TZMultiMasterQuery.ParamLinkDataChange(Sender: TObject);
var
i: Integer;
Param : TParam;
Field: TField;
begin
if not Assigned(ParamLinkPairs) then Exit;
i := ParamLinkPairs.IndexOfObject(Sender);
if i = -1 then Exit;
Param := Params.ParamByName(ParamLinkPairs.Strings);
if not Assigned(Param) then Exit;
Field := (Sender as TFieldDataLink).Field;
if not Assigned(Field) then Exit;
Param.AssignFieldValue(Field, Field.AsVariant);
if Active then Refresh;
end;

I belive you can imagine the others, they are really simple.

Posted: 03.02.2007, 15:28
by mdaems
That was quick...
Can't you attach a file to your posts on this forum? (Use the preview button just below the quick reply box or edit an existing message) Just zip the changed files or make an SVN diff.

Could you provide a very small example prog (and data creation SQL)? I suppose you made one to test your trick.
So we may figure out how to set the necessary dataset relations.

Mark

Posted: 03.02.2007, 19:07
by zsoca
Hi friends!

So, here is the first version of the component, and an example on it, with layers, areas and objects.

Install the component, and create a database based on the SQL script you find in the DB directory (or use the firebird database you can also find there).
In the demo setup the connection, and try it. In the pas file, you can see how the links can be set up programatically. Soon a visual property editor will follow.
I would like to ask the more involved colleagues to check the yource of my component, and propose chenges in order to optimise it.

Best regards, Zsolt Balanyi