Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Persistent Class - problem with inheritance

ralf_wenzel_heuristika
Active Participant
0 Likes
3,163

Hi.

According to SAP Help, I want to develop persistent classes with inheritance.

I have a DB table, which is structured very similar to system table INDX. This table contents two kinds of records, which are differed by the field RELID. This means, I have records with RELID = SO and records with RELID = SP. In the current, very procedural coding, there are many IFs (IF RELID = SO....elseif RELID = SP .... endif). I want to get rid of them and in addition to that, there are many reasons to make an object oriented application of this program. Maybe in the future, there will be more RELIDs and each ELSEIF has to be extended.


So let's get to object orientation - down to the persistence layer.


Because there is some coding, which is depending on this difference, I want to have two kinds of persistent objects (= two different classes), both classes are inheriting from the same superclass. In the superclass, I want to code the coding, that has to be proceeded by all records, in the subclasses the coding, which is special for this RELID (means: the coding with the IF and ELSEIF-Coding).

So I defined the superclass ZCL_XYZ and the inheriting subclasses ZCL_XYZ_SO and ZCL_XYZ_SP.


If there is another RELID in the future, I would make another class only with the special coding, related to the new RELID. This makes sense!

At First, I read all the relevant records into an static internal table, which saves the key fields of the table and the object (I think, this is called a "Multiton Design Pattern"). In particular, this internal table stores all persistent objects and assigns them to the related DB record. The columns of this internal table are: The key fields of my DB-table (let's call the table XYZ, same structure like INDX) and an additional column for the objects (type ref to ZCL_XYZ). In column ZCL_XYZ are all objects of a subtype of ZCL_XYZ. Each object stores the content of the relating database record in his attributes.

The problem is: If I want to set one of the DB fields (i. e. XYZ-LOEKZ), I call the SET_LOEKZ-method of my persistent subclass. For instance:

READ TABLE instances assigning field-symbol.....

index ....

<instance>-persistent_object->SET_LOEKZ( ABAP_TRUE ).

This works fine. I can see in my persistent object, that the field has been filled with an 'X'. To get this X into the record on the database, I have to do a commit work. And this is the problem. After commit work, all attributes (RELID, LOEKZ, etc.) of ALL of my persistent objects are empty. In my internal table "instances" I can see all objects, but they do have all empty attributes.

I don't know, why. I searched and debugged for days without finding a reason. It seems, that all objects are rebuilt, but why - and why with empty attributes?

Today I read the linked document in the SAP Help (see above, at the beginning of this posting), and that I need a type identifier field in my DB table. I added this type identifier field, added it into the mapping rules as type identifier field, but when I want to activate the persistent class, I get the following syntax error:


The component TABLE_LINE is not contained in key "PRIMARY_KEY" of table "KEY_TAB_FOUND_LOCAL", or the key is not statically known.


The coding line with the syntax error is in IF_OS_CA_PERSISTENCY~GET_PERSISTENT_BY_KEY_TAB is this statement:


            read table key_tab_found_local
                  transporting no fields
                  with table key table_line = business_key.


This is a statement in the generated coding of my persistent class. KEY_TAB_FOUND_LOCAL is an internal table - type standard table of BUSINESS_KEY with default key!


I don't know, what kind of problem causes the syntax error in the automatically generated coding. If I delete the type identifier field from my DB-table XYZ, the activation process works fine, but I have the problem with the deleted object attributes after COMMIT WORK.


What I am doing wrong???? How can I get my application running with inheriting persistent classes???


There is just ONE answer, I don't want to hear: "Don't use persistent classes".   I want to use them, the SAP Help says it works. I don't want to rebuild my application. I just want to make it working.

1 ACCEPTED SOLUTION
Read only

jwood_bowdark
Active Participant
0 Likes
2,799

Hi Ralf,

So I tried to set this up locally and think I was able to get this work as described. The screenshots below show the XYZ table I created and the corresponding persistence representation in ZCL_XYZ. The subclasses (e.g. ZCL_XYZ_SO) simply inherit the persistence mapping, so I didn't change anything there.

Here's a snippet of the test code I created:

DATA lo_xyz TYPE REF TO zcl_xyz.
DATA lo_xyz_so TYPE REF TO zcl_xyz_so.
DATA lo_xyz_sp TYPE REF TO zcl_xyz_sp.

TRY.
  lo_xyz_so=
    zca_xyz_so=>agent->create_persistent(
      i_relid = 'SO'
      i_srtfd = 'SO_SUBCLASS' ).

  lo_xyz_so->set_loekz( abap_true ).
  lo_xyz_so->set_aedat( sy-datum ).
  lo_xyz_so->set_usera( sy-uname ).
  lo_xyz_so->set_pgmid( sy-repid ).
  lo_xyz_so->set_begdt( sy-datum ).
  lo_xyz_so->set_enddt( sy-datum ).

  lo_xyz_sp=
    zca_xyz_sp=>agent->create_persistent(
      i_relid = 'SP'
      i_srtfd = 'SP_SUBCLASS' ).

  lo_xyz_sp->set_loekz( abap_true ).
  lo_xyz_sp->set_aedat( sy-datum ).
  lo_xyz_sp->set_usera( sy-uname ).
  lo_xyz_sp->set_pgmid( sy-repid ).
  lo_xyz_sp->set_begdt( sy-datum ).
  lo_xyz_sp->set_enddt( sy-datum ).

  COMMIT WORK.
CATCH cx_root.
ENDTRY.

The same code works if I create the entries using the superclass. From here, I played around and created some helper methods in the subclasses and that worked out OK, too. I didn't bother with implementing a multiton or anything like that, but hopefully I captured the essence of what you're looking for.

Anyway, let me know if I'm missing anything here with your use case. Otherwise, I hope this helps.

Thanks,

James

9 REPLIES 9
Read only

jwood_bowdark
Active Participant
0 Likes
2,800

Hi Ralf,

So I tried to set this up locally and think I was able to get this work as described. The screenshots below show the XYZ table I created and the corresponding persistence representation in ZCL_XYZ. The subclasses (e.g. ZCL_XYZ_SO) simply inherit the persistence mapping, so I didn't change anything there.

Here's a snippet of the test code I created:

DATA lo_xyz TYPE REF TO zcl_xyz.
DATA lo_xyz_so TYPE REF TO zcl_xyz_so.
DATA lo_xyz_sp TYPE REF TO zcl_xyz_sp.

TRY.
  lo_xyz_so=
    zca_xyz_so=>agent->create_persistent(
      i_relid = 'SO'
      i_srtfd = 'SO_SUBCLASS' ).

  lo_xyz_so->set_loekz( abap_true ).
  lo_xyz_so->set_aedat( sy-datum ).
  lo_xyz_so->set_usera( sy-uname ).
  lo_xyz_so->set_pgmid( sy-repid ).
  lo_xyz_so->set_begdt( sy-datum ).
  lo_xyz_so->set_enddt( sy-datum ).

  lo_xyz_sp=
    zca_xyz_sp=>agent->create_persistent(
      i_relid = 'SP'
      i_srtfd = 'SP_SUBCLASS' ).

  lo_xyz_sp->set_loekz( abap_true ).
  lo_xyz_sp->set_aedat( sy-datum ).
  lo_xyz_sp->set_usera( sy-uname ).
  lo_xyz_sp->set_pgmid( sy-repid ).
  lo_xyz_sp->set_begdt( sy-datum ).
  lo_xyz_sp->set_enddt( sy-datum ).

  COMMIT WORK.
CATCH cx_root.
ENDTRY.

The same code works if I create the entries using the superclass. From here, I played around and created some helper methods in the subclasses and that worked out OK, too. I didn't bother with implementing a multiton or anything like that, but hopefully I captured the essence of what you're looking for.

Anyway, let me know if I'm missing anything here with your use case. Otherwise, I hope this helps.

Thanks,

James

Read only

0 Likes
2,799

I did the following steps:

1. Creation of transparent table

   - Key fields same as INDX

   - Type Identifier (not in key)

   - additional attribute columns especially CLUSTR and CLUSTD

2. Creation of persistent class

   - creation protected (automatically selected)

   - not final

   - persistence mapping all fields

   - generator settings: activate checkbox "generate methods for query"

   - SAVE

   - ACTIVATE

   - Activate Class Agent -> Yes

   - => Activation runs into error, I described ("The component TABLE_LINE....")

Note: This is the superclass, I did not implement any inheritance, yet!!!

If I delete the type identifier column from table, it works. But I need it for inheritance later...

(sorry for screenshot anonymization)

Read only

0 Likes
2,799

Hi,

I am working with persistency since 2002. In 2007 I designed and developed an add-on for FI/CO, importing, displaying, modifying and posting data, completely written in OO and persistency.

After Commit, my application does a Full Retrieve again, so I did not run into that Situation. In documentation can be read, that after commit all persistent objects are invalidated ... so, may be a feature ...

---

I tested inheritence with persistence on Mini SAP with Sap-Basis and Abap =731 (System_Status)

I created a table according to SFLIGHT with OS_GUID as first non key field.

I created a persistent superclass (not final) and two subclasses _aa _az (final). Generating superclass is fine! Generating subclasses causes error (Interface should not defined again in subclass) but when the specific line is marked as comment (*) it works.

Testroutine reading specific CARRID entries from SFLIGT (AA or AZ) and creating persistent objects with my individual agents _aa and _az. After commit the records are in the table, with different OS_GUID for AA and AZ. These GUIDs are matching the GUIDs, defined in the class-constructors of the agent-classes.


Reading (get_persistent by keytab) is done by superclass.  Every returned object (single ref or OSREFTAB) has the desired type. (obiously derived from OSGUID).

(If created via superclass, the objects cannot be separated)

Redefined methods will return the desired values from the subclassess ...

So far ... working ... within this small test-Scenario.

---

From my opinion, I am using persistecy frequently (never collecting changed records and writing with "on commit" or sth. else, never writing agents or factories by myself).

Inheritece with Persistence:

In my Project 2007 I had the same situation ... lots of datasets ... nearly the same.

I used persistency for storing and retrieving only. The individual routines were put into a "normal" Class-Scenario (with inheritence). Via customizing it was defined and derived, which subclass should be used for specific record-types.

May be, that's the choice in Ralfs Case!

Best Regards

Bert

Read only

0 Likes
2,799

Hi Ralf,

OK, I went back through your description and applied the requisite changes to my demo to reproduce your error. As near as I can tell, this is a function of a bug in SAP's code generator. Here, because the key of the KEY_TAB_FOUND_LOCAL internal table was defined generically, you couldn't have a non-character field as part of the key. The workaround I came up with was to redefine the SRTF2 field as a NUMC(10) field so that the key constraints would line up properly. Once I made this change, everything seemed to work for me. Note that you may have to blow away your classes to make this work - the generator seemed to have a hard time cleaning up its mess.

Hope this helps.

Thanks,

James

Read only

0 Likes
2,799

Thanks for helping me, James. I cannot change the SRTF2 field's type, unfortunately. So I have to delete the persistent classes.

Read only

0 Likes
2,799

Bummer. In that case, you might want to see about opening up a customer message with SAP on this. I think just a little bit more intelligence on the part of their code generator would allow this to work as-is. I expect that Persistence Classes are used so infrequently in the community that perhaps SAP's never stumbled across this before...

Read only

0 Likes
2,799

Hi James,

you are right ... these Object-Services are somehow "not" used.

When I used them, when programming for SAP ... none of the contacted SAP empoyees or programmers had ever heard or read of them.

(I got a complete read, create, write, commit, rollback scenario working in a minimum of time ... not knowing, what "upper" transaction-level was doing in case of rollback or commit ...)

The documentation is weird, it is hard to understand, what you can do and how you should work with all this kind of stuff.

But, be honest, using INT4-Field in Table key AND trying to use inheritence ... that would not have been the main testing issue by the developers (Inheritence had obviously never been tested too, as could be determined from the invalid coding, created by code generator).

For standard cases it is very useful, ... if you know "what is working" 🙂

Best is, to take Object-Services into consideration BEFORE designing the application ... 😉

Best Regards

Bert

Read only

0 Likes
2,799

I strictly disagree. Even the most simple things like "SELECT .... WHERE .... IN ...." are impossible.

I rarely have seen a technology, which is as incomplete as Object Services. A bug like this, unfound in more than ten years, that is just unbelievable embarrassing.

I have pushed this technology through all arguments with / against the customer, now I am standing in a pile of shards, the customer has paid for a huge technology and gets an error report.

I won't try any experiments from now on, but implement the well known technologies.  I know, a simple select works, so I will use it - and not the f*cking crap, the marketing guys making propaganda for.

Read only

0 Likes
2,799

Hi Ralf,

I can certainly appreciate your frustration. Coming from the Java world, ABAP Object Services is definitely a letdown from JPA/JDO/Hibernate. Before you completely scratch the use of frameworks for this stuff though, I would encourage you to spend some time looking at the BOPF. This framework is quite powerful and can really save you a ton of time when it comes to building custom business objects. On the development side of things, you'll also find that SAP enforces fewer restrictions regarding how tables are mapped to object nodes, etc. Anyway, worth a look at some point.

Thanks,

James