Live BInding and Table Inheritance

Wagner,


I came up with a new issue that I am not sure how to solve it.

Here is a screen of the form I am designing, it is not fully functional yet:

http://snag.gy/eFQGs.jpg

There is a TADS (TAureliusDataSet) for the Alunos Listview

Each of the other ListViews are linked by the DataSetField with the correspondent TADS.

So, when changing the Alunos record all the other ListViews will present the correspondent data.

Works just fine. I am using SourceCriteria for the Alunos.

Each one of the Details TADS are displaying its base class. LIke the example on help about TAnimals, TDogs and TBirds.

I have many inheritend entities for each of the Details.

For example "meio contato", I have email and "Telefone" both are descendants of the same base entity.

Then showing in the listview I present the base class.

However I need to ADD and EDIT what is there. And I want do that using LIveBinding.

I came with a solution for editing, not sure if this is safe. I  have not find a way for inserting.

Let me explain Editing:

I am using TPopup with fields since Tpopup is hidden and when you make it show look like an dialog. At design time it is available in the same form then I can wire it to the BindSources already in use.

The problem is that for example "Meios Contato" is connected to a BindSource from a TADS that only displays the fields from the base class. For the ListView this is fine.

But for editing I have particular fields for each descendant. And very different ones.

I made the following:

- created a BindSource and TADS for each of the needed descendants of the base class
- wired this BindSource where I have the fields.
- When the user click EDIT I get from TADS.Current<> the current object for edition
- I use this particular object and use SetSourceObject(object) from the descendant I want.
- use the Edit and then Post (It gets saved)
- I use then TADS.Refresh from the base class DataSource to get the original ListView updated.

Just work very nicely, and was amazingly simple.

However I am not having the same luck with ADD.

I am using the follwing steps:
- create a new TEntityTelefone (for example)
- I use the TADS.SetSourceObject()
- Open and Edit, then I have a blank record to edit in my livebinding TPopup with all the particular fields;
- the user click SAVE:
- TADS.Post : the record gets saved on the table with the new telefone.
- Now I need to add the new record to the Selected Aluno, and this is all the problem...

If I could add this new object to the TADS "meios contato" the problem could be solved. (again, this is the TADS details that is connected to the TADS alunos that is a master)

What i tried: 
- Got the current TEntityAluno by TADS.Current<>
- Aluno.MeiosContato.Add(My new telefone object that i got by TADS.Current<> from the work table>
Manager.SaveOrUpdate(TEntityAluno)  (because there is this new join relation)

and nothing happens... no SQL generated and no relationship made between the new record and Aluno.

Funny thing is that in the Detail ListView it is presented after the TADS.Refresh.

There is a lot of abstraction in my classes, but this is snipped of my code:

add command:
              Telefone := TEntityMeiosContatoTelefone.Create;
              with Model.DataSet['adsmeioscontatotelefone'] do
              begin
                SetSourceObject(Telefone);
                Open;
                Edit;
              end;
              Model.Context.Cookie.Store('meioscontato.add', True);
              View.Popup['meioscontatotelefone.popup'].Show;

This creates and empty Telefone record for use

Save or Close command:

      case IndexText(AParam, ['close', 'save']) of
        0 : begin
              Model.DataSet['adsmeioscontatotelefone'].Cancel;
            end;
        1 : begin
              Model.DataSet['adsmeioscontatotelefone'].Post;
              if Model.Context.Cookie.TryRetrieve('meioscontato.add', false) then
              begin
                Aluno := Model.DataSet['adsaluno'].Current<TEntityAluno>;
                Aluno.MeiosContato.Add(Model.DataSet['adsmeioscontatotelefone'].Current<TEntityMeiosContatoTelefone>);
                Model.SaveOrUpdate(Aluno);
              end;
            end;
      end;

      Model.DataSet['adsmeioscontato'].Refresh;

this code works with both Add and Edit, In case of Edit just saving (TADS.Post) is all that is needed because I have set the SAME object from the other TADS.

However for the ADD command I need to create and associate it to the list from Alunos.

I dont know what to do in this case. How can I update my detail list with the new created object?

This is how is defined my "Meios Contato": 

    [ManyValuedAssociation([TAssociationProp.Lazy], [])]
    [ForeignJoinColumn('FJIDMEIOSCONTATO', [])]
    FMeiosContato: Proxy<TList<TEntityMeiosContato>>;

    property    MeiosContato: TList<TEntityMeiosContato> read GetMeiosContato;

Just MeiosContato.Add(new ojbect) is not doing the work.

This "meios contato" is not in the TEntityAlunos, it is part of the anscestor TContato. I have 3 levels right now:

TContato
TContatoFisico(TContato)
TAluno(TContatoFisico)

I have many cases like that, and I need to create a TPopup for each case and bind visually each one to the particular BindSource.TADS, but the Master Details are always based on the base classes.

Thank you

Just to have a partial idea of the frame in design view with the livebindings:


http://snag.gy/GsEtZ.jpg


I forgot to show this:


                Model.DataSet['adsaluno'].Edit;
                Aluno := Model.DataSet['adsaluno'].Current<TEntityAluno>;
                Aluno.MeiosContato.Add(Model.DataSet['adsmeioscontatotelefone'].Current<TEntityMeiosContatoTelefone>);
                Model.DataSet['adsaluno'].Post;

This code actually does what I am looking for, however I need to EDIT and POST the Main TADS and that was something I was trying to not do. And it also seems weird,

All seems to be ok. The detail list is part of the parent record, so you need to edit and post it to make changes be performed. If the detail object is already saved, note that adding it to the detail (meioscontato.Add) doesn't do anything until you call Flush. Have you tried calling Flush after all the process to perform pending changes?


Finally, why do you use a different dataset for each descendant? Why not using a single dataset, and put all possible fields there? According to dataset documentation, if the field doesn't exist in that class, no error is raised, the field is just ignored and contains null value.

How can I have all possible field in one dataset? I use the option of loading from the package to fill in the dataset, and it brings its fields and inherited ones, however I have other tables that are "sisters", descend from the same base table. 


Based on that I have decided (maybe wrong) to use the base class table for listing. Since Aurelius publish non mapped properties I have created standard properties that can be override in each subclass, then each subclass return what is more appropriate for displaying in the listview.

My problem now is that after I have upgraded to last version, there is a wrong behavior on the code. When saving on of this tables Aurelius is getting in loop calling an UPDATE sql for a tablet that is not apparently related.

I am trying to identify why that.

I will give a try on the Flush. 

You just need to add the fields manually.

If you have more info about the bug, just let me know, so we can fix it.