cancel
Showing results for 
Search instead for 
Did you mean: 

Personalization Keys in native iOS Application

Former Member
0 Kudos

Hi there,

I just started with SUP development for my bachelor thesis. The Server is set up and the communication between the simulator and the server works fine. The Datasource is a SAP CRM System (BAPI RFC).

To get started, my first task is to create a simple process:

- The user searches businesspartners by partnerid/city/email

- A list of BPs is shown

- The user selects a BP

- The details of that BP are shown

Therefore I created a MBO with the input parameters city, partnerId and email and some output parameters (BP_NUMBER, BP_DESCRIPTION). The input parameters are capsulated in a structure. Then I created a personalization key for the load parameter (the structure).

in my code, I can now set those load parameters via the personalization key and execute the query

FirstApp_PersonalizationParameters *pp = [FirstApp_PersonalizationParameters getPersonalizationParameters];

FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER *pk = [FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER getInstance];

[pk setP_PARTNERID: @""];

[pk setP_CITY: @"Hamburg"];

[pk setP_EMAIL: @""];

[pp setGpSuchenPk:pk];

[pp save]

... = [FirstApp_Geschaeftspartner findAll];

This only works, if the personalization parameter's storage type is set to Server. Transient or Client will not work. Is that a correct behaviour? Is this whole procedure the correct way to pass user-input-data to a query?

The next step would be that I take the BP_NUMBER of a selected business partner and pass this value to another MBO which gives details to a business partner.

It would be very helpful to get some feedback, if this is the correct way to do it.

Thanks in advance

chumbalum

Accepted Solutions (1)

Accepted Solutions (1)

Former Member
0 Kudos

Hi,

I finally got it working. The output tables of my BAPI don't have a primary key column, which caused a strange behaviour (first 1 resulting rows, then 0, then 1, then 0 and so on).

At first, I created a personalization key for the load parameter: PK_PARTNER

For each output table:

  • In the Load Parameters tab, I mapped the personalization key for the load parameter (PK_PARTNER)
  • In the Attribute Mapping tab, I added a new attribute called Z_PRIMARY and checked the primary key checkbox
  • In the Load Parameter tab, I set the "propagates to" field of my load parameter to Z_PRIMARY

Now I can query properly:

Mobile_PersonalizationParameters *pp = [Mobile_MobileDB getPersonalizationParameters];

[pp setPK_PARTNER:bpId];

[pp save]

while([Mobile_MobileDB hasPendingOperations])

{

     [NSThread sleepForTimeInterval:1];

}

[Mobile_MobileDB beginSynchronize];

I then wait for the SYNCHRONIZATION_FINISH event caught by my callback handler and execute my findAll query.

I switched back to Unwired Workspace 2.1.0, by the way.

Thanks for your support,

Christian

Answers (6)

Answers (6)

Former Member
0 Kudos

Hi experts,

I'm still facing some problems with SUP. I guess the personalization keys which match the input parameters of my MBOs are ok. Retrieving data still doesn't work 100%.

Here's the behaviour I noticed.

After setting the PK in my code and calling the save method, the pk will be sent to the unwired server. The unwired server then calls the BAPI to refresh it's CDB. I checked the input and output values with an external breakpoint in SAP: the input parameter is transmitted correctly and the return value is a table with 100 rows. In the meantime, the device is waiting for the function to finish (blocking after the save command). After all data is transmitted the save command returns and the findAll is executed. On client side, the result has only 92 rows. This also happens with less resulting rows: 24 rows in BAPI return - 19 on client side.

I also noticed another problem.

I have that MBO which gives me details about a business partner. The business partner id is an input parameter, for which I created the personalization key. First, I created the MBO with one input parameter and an output parameter, which is a table with several columns for the details:

input: BpId

output: table(Firstname, Lastname, BpType, Name1, Name2, + several more columns)

With this MBO, the findAll query doesn't work. No row is returned. I then modified that MBO by deleting most of the output parameters. So the new MBO was:

input: BpId

output: table(Firstname, Lastname)

After this, findAll returns a row.

Somewhere must be data loss. The BAPI return values are fine. So either the unwired server doesn't save them, or they aren't transmitted correctly to the device (ios simulator)

Any ideas?

Thanks & Greetings,

Christian

Former Member
0 Kudos

Hi again,

today we upgraded to SUP 2.1.3 with patch 02. This has at least fixed the use of transient personalization keys. Saving them finally causes activity.

But I'm still struggling with the odd behaviour. Now the first findAll (to search business partner by city) is also affected. The programm launches, I do the first search by searching for BPs in Hamburg and get the list of BPs,that I would get with the default values in the personalization parameters. If I press the search button again, the correct list will be shown.

My theory is the scenario shown above. As the personalization parameter is saved, it will be synchronized with the Unwired Server. The Unwired Server now refreshes its consolidated database based on the new personalization parameter. It then has to synchronized this data with the device. Before this process is completed, the findAll is already executed and a a list base on the old data is shown.

There must be a way to get a "online-like" behaviour, or am I wrong?

User enters city and presses search -> SUP makes a bapi call -> result is shown to the user

just it like would happen in the SAP GUI

I really appreciate your help so far

Greetings,

Christian

Former Member
0 Kudos

I quote this post, because our guess was wrong and not always reproducable.

Hi,

transient personalization keys won't work. But I can live with this by setting the storage type to server.

We found out, why the results can be somewhat random (But we are not 100% sure about this).

The above image shows my problem. When the user fills in a business partner ID and hits the search button, the personalization parameter will be set and saved. When the server receives a new personalization parameter, it will update the consolidated database base on the new personalization key. Therefore it execute the BAPIs on the SAP system to get the data. If the consolidated database is update, the server will synchronize the changes to the mobile device. This whole procedure takes too much time.

In my application the findAll is called, before the synchronization process is completed. So the findAll will return results based on an old/mixed local database. If I wait 20 seconds and call findAll again, it will return the data based on the up-to-date local database. This asynchronous behaviour is a bit unsuitable for my scenario.

I'm using a while loop after saving the new personalization key like this:

while([DB hasPendingOperations])

{

     sleep

}

as mentioned in the Student Guide for SUP 2.1, but this won't cover this issue. So I want to know, if there is a workaround for this problem.

Thanks,

Christian

_IvanFemia_
Active Contributor
0 Kudos

Christian,

You have to wait the CallbackHandler event from SUP, once sync is finished you can load data from your local DB.

Regards,

Ivan

Former Member
0 Kudos

Hi Ivan,

I'll give it a try

Thanks.

Message was edited by: Christian Hoff

Former Member
0 Kudos

I'll reply here to have some more space.

This is the simple scenario I want to implement:

  • The user searches business partner in a city
  • BPs in that city are shown in a list
  • The user selects a BP
  • The details for that BP are shown

To do this, I need two BAPIs which will be represented by two MBOs. The first on is called Z_BUPA_BOL_SEARCH.

I select the input parameter “SUCHPARAMETER.CITY1” and the output parameter, which is the table called “SUCHERGEBNIS”

I delete most of the output parameter mappings because I just need two of them. After this I finish the wizzard.

As the user shall be able to insert a city name as search criteria, I create a transient personalization key called BpSearchPP for the load parameter.

I don’t make any further configurations in SUP Workspace. So I generate the code and deploy the MBO.

To test this scenario, I created a simple application which does the following:


SUPConnectionProfile *cp = [FirstApp_FirstAppDB getSynchronizationProfile];

[cp setDomainName:@"default"];

if([FirstApp_FirstAppDB databaseExists])

{

    [FirstApp_FirstAppDB deleteDatabase];

    [FirstApp_FirstAppDB createDatabase];

}

[FirstApp_FirstAppDB startBackgroundSynchronization];

[SUPMessageClient start];

[FirstApp_FirstAppDB beginOnlineLogin:@"supAdmin" password:@"...."];

[FirstApp_FirstAppDB subscribe];


- (IBAction)actionButtonPressed:(id)sender

{

    FirstApp_PersonalizationParameters *pp = [FirstApp_PersonalizationParameters getInstance];

    FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER1 *pk = [FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER1 getInstance];

    [pk setCITY1:_inputText1.text];

    [pp setBpSearchPP:pk];

    [pp save];

    [FirstApp_FirstAppDB synchronize];

    while([FirstApp_FirstAppDB hasPendingOperations])

    {

        [NSThread sleepForTimeInterval:1];

    }

    SUPObjectList *gp = [FirstApp_BusinessPartner findAll];

    MBOLogInfo(@"Rows returned: %i", [gp length]);

}

If I type in a value for the personalization key "CITY1", it will have no limiting effect on the result set. So I guess I misunderstand something.

I'm using SUP 2.1.0, Xcode 4.3.2, develop with the iOS 5.1 SDK and test the app in the iPad simulator.

Thanks for your support,

Christian

Former Member
0 Kudos

Hi Christian,

I have not tried to make a PK of list type but it should not make any difference with a normal one, and everything seems fine at your scenario, except for the Personalization Key paintscreen... you have it defined like nullable, AND with a nullable value, this is the strange synchronizacion behavior that i was talking about, seems like Workspace does not recognize this defined personalization key, and does not create it well... in my case i solved it with:

1)Fast test - Not recommended* i did a double synchronization

(im not really sure if these methods are pure RBS methods, try to make a MBS Synchronization, since you have the 2.1.)

with 2.1.3 i did,

    [FirstApp_FirstAppDB synchronize];

    [FirstApp_FirstAppDB synchronize];

 

OR

2) Redefine the nullable Personalization Key with some default value. Type some not nullable default vaules at your PK

If the problem persist, then upgrade to SUP 2.1.3.

I have SUP 2.1.3, and XCode 4.4.1 with iOS 5.1.1, and its working fine (also did some testing with XCode 4.5.2 and iOS6, and found some problems but with the iOS APIs).

Former Member
0 Kudos

I'm not able to set the personalization key to not-nullable; the function is grayed out. I think this happens because the data type of the PK is a structure. To test your idea, I made another MBO with the second BAPI. This one takes a business partner ID as an input parameter, which cannot be null. This results in the same behaviour. The values of the PK which will be set in my code, will not take effect. If the save command is called, just nothing happens. With storage type set to server, I can at least see activity in the MBO Logger.

The double call of synchronize didn't make any difference.

As I'm developing MBOs I really think that the whole concept is intended for ordinary database tables. The difference in normal database tables is, that the attributes which filter the results are in the table itself. In BAPI, input parameters which will filter the resultset are not part of the resultset itself. For example:

In normal database

  • tbl_customer: ID, Firstname, Lastname, City

With this table, I can easily create a MBO for the table and create a object query with city as parameter.

In BAPI

  • input parameter: city
  • output parameter: ID, Firstname, Lastname

This makes it impossible to create object query with 'city' because it's not part of the resulting table itself

I know the difference between Objecty Queries and Personalization Paramets. But using Load Parameters is the only way to realize the same behaviour with BAPI. And I'm not getting it to work. I'm really running out of ideas.

Thanks for your support,

Christian

Message was edited by: Christian Hoff

Former Member
0 Kudos

Hello Christian,

About the City/Query filter, you can propagate the input parameter to the results.

To do this on the Diagram Editor View (view of your mbos):

-Add an attribute to your already defined MBO, name it i dont know... "CityExample"

Go on the Load Parameters of this MBO:

- Identify the input that you want to propagate, in this case is the city input.

- Click on the cell of "propagate to attribute", and then you select the CityExample.

- Then test your MBO with Preview, to check that it works.

In your next search results, it will show you all of the output information + the input that you sent.

- Generate your Query, and test on device.

Regards,

Daniel

_IvanFemia_
Active Contributor
0 Kudos

Hi,

Personalization Parameters are used in combination to synch parameters to retrieve data.

I suggest to refer to the official documentation for the complete definition of these Personalization APIs

Even more in this link to the official documentation there is a very clear definition of the Type of Personalization Keys

Hope this could help

Regards,

Ivan

Former Member
0 Kudos

Hi Ivan,

I already read the documentation about personalization parameters. But I don't think they fit my requirements. I have a BAPI with input and output parameters (which are tables).

I then created the MBO:

After that, I created a personalization parameter for the business partner id and set that pp in the load parameter.

U say, that personalization parameters always go with synchonization parameters. But synchronization parameters can only be mapped to attributes from the output tables.

I simply want to pass a business partner id as the input parameter to get a single business partner. The first query works but the second one (this one) sometimes returns a row and sometimes  doesn't

rakshit_doshi
Active Contributor
0 Kudos

Hi,

It is not a compulsion to use a Synchronization parameter with a personalization parameter. The document does say that but it works fine without it as well. Even we had the same scenario wherein the BAPI took a number of parameters as input and returned a table as an output parameter.

I just created a personalization key of the type transient and thats it. I just added the personalization key to the respective input parameter from MBO Properties--> Attributes-->Load Arguments.

Generate the code. Set the value of Personalization Parameters and save the personalization key.

It will definitely work.

Hope this helps,

Thanks,

Former Member
0 Kudos

Hi Rakshit,

that's totally the way I did it. But I run into a weird behaviour. The values stored in the personalization keys will only take effect, if the save command is called before the subscription of the database.

in code:

[TestDb subscribe]

[pp setCityName:@"Hamburg"]

[pp save]

will not affect the result. But this will:

[pp setCityName:@"Hamburg"]

[pp save]

[TestDb subscribe]

I guess the normal way is to subscribe the database once. I would use the second way as a workaround, but I have that scenario:

- user enters input parameters in a search form

- user presses the search button (thats the time, the new pp values will be set)

- result is shown

The subscription process takes some time and if the query is executed right after that, it will not take effect. I could do a sleep after saving the pp and subscribe the db, but that seems as a bad solution for me.

Thanks,

Christian

rakshit_doshi
Active Contributor
0 Kudos

Hi,

You have to save the personalization key before calling the database. Can you please explain why are you using subscribe. Instead of using subscribe using synchronize() or beginsynchronize()  API.

This will produce expected results.

Hope this will help,

Thanks

Former Member
0 Kudos

Hi,

I'm getting random behaviour on queries. That's why I try different ways. This was actually my first solution:

- Application launches

- Check if SuP Login data are provisioned (they are)

- delete and recreate the local database (so shown in various documentations for test purpose)

- start background synchronization

- start the sup message client

- app will try to connect to the sup server

- on connection success, login with credentials

- subscribe the database

Until this point, this makes sense to me.

The next step is to execute the first query which gets a list of business partner core data. So I do the following:

FirstApp_PersonalizationParameters *pp = [FirstApp_FirstAppDB getPersonalizationParameters];

FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER *pk = [FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER getInstance];

  

[pk setNAME_ORG1:[[self suchenTextField] text]];

[pk setNAME_ORG2:@""];

[pk setNAME_ORG3:@""];

[pk setNAME_ORG4:@""];

[pk setCITY1:@""];

[pk setPARTNER:@""];

[pp setGpSuchparameter:pk];

[pp save];

while([FirstApp_FirstAppDB hasPendingOperations])

{

    [NSThread sleepForTimeInterval:1];

}

[self setGpList:[FirstApp_Geschaeftspartner findAll]];

pk a personalization parameter with attributed: NAME_ORG1, NAME_ORG2, NAME_ORG3, NAME_ORG4, CITY1 and PARTNER

So I set the values of those attributes, save the peronalization parameter and execute the findAll query. Here occures the first strange behaviour: This will only work, if the storage type of the personalization parameter is set to 'Server'. I'd rather like it to be 'Transient'. If the storage type is set to 'Transient', it will have no effect on the query.

So I got this list of core data. The core data includes the BP_NUMBER, which shall be the input parameter of the next query. So I do the same thing as above: set the value of another personalization parameter, save the personalization parameter and execute the query:

FirstApp_PersonalizationParameters *pp = [FirstApp_FirstAppDB getPersonalizationParameters];

[pp setGpDetailParameter:[gp BP_NUMBER]];

[pp save];

while([FirstApp_FirstAppDB hasPendingOperations])

{

    [NSThread sleepForTimeInterval:1];

}

   

SUPObjectList *gpDetailList = [FirstApp_GeschaeftspartnerDetail findAll];

This time, the number of rows will sometimes be 0 or sometimes 1, even for the same business partner. The value will switch by restarting the application, so I guess it's be a problem with the synchronization of the personalization parameters. So:

- I start the app

- I search for BPs in Hamburg

- I got BPs for Hamburg

- I select the first BP

- I got no Details for that BP (0 rows returned)

- I close the app (terminate the simulator)

then

- I start the app

- I search for BPs in Hamburg

- I got BPs for Hamburg

- I select the first BP

- I got a Detail for that BP (1 rows returned)

So I really don't know, what causes this issue. The first query (searching for BP core data) always give me the right results, but the second query is just random.

Former Member
0 Kudos

Hello Christian,

First of all:

1) Is your Personalization key nullable, and have a "null" as a default value (in your worskpace/MBO)? if it does, it will have a really strange behaviour at synchronizations, please change the default value to some random value and then at the XCode type whatever you want.

2) The way that i use transient personalization keys at iOS, its like this:

PersonalizationParameters *pp = [PersonalizationParameters getInstance];

pp.firstpk = @"value";

pp.secondpk = @"value";

[pp save];

//Then Synchronize

[DB synchronize];

or

[DB synchronize:@"synchronizationgroupname"];

or

[DB synchronize:@"synchronizationgroupname" withListener:[CallbackHandler getInstance]];

/*---------------------------------

in your case

-----------------------------------*/

FirstApp_PersonalizationParameters *pp = [FirstApp_PersonalizationParameters getPersonalizationParameters]; 

pp.NAME_ORG1=[[self suchenTextField] text];

pp.NAME_ORG2=@"";

pp. bla bla bla

[pp save];

then synchronize

[FirstApp_FirstAppDB synchronize:@"synchgroupname"];

Former Member
0 Kudos

Hi Daniel,

that's the way I did it. This is the original extraction of my code:

- (IBAction)suchenButtonPressed:(id)sender

{

    FirstApp_PersonalizationParameters *pp = [FirstApp_FirstAppDB getPersonalizationParameters];

    FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER *pk = [FirstApp_Z_BUPA_BOL_SEARCH_SUCHPARAMETER getInstance];

      

    [pk setNAME_ORG1:[[self suchenTextField] text]];

    [pk setNAME_ORG2:@""];

    [pk setNAME_ORG3:@""];

    [pk setNAME_ORG4:@""];

    [pk setCITY1:@""];

    [pk setPARTNER:@""];

   

    [pp setGpSuchparameter:pk];

    [pp save];

   

    [FirstApp_FirstAppDB synchronize];

   

    while([FirstApp_FirstAppDB hasPendingOperations])

    {

        [NSThread sleepForTimeInterval:1];

    }

   

    [self setGpList:[FirstApp_Geschaeftspartner findAll]];

   

    [[self tableView] reloadData];

}

I added the synchronize after the save command, as you told. With personalization parameter store type set to transient and having default values, this procedure has no effect. I always get the unfiltered list of business partners.

Former Member
0 Kudos

Hello Christian,

From what i can see you are having a problem of construction/understanding of MBOs. The personalization Keys have almost nothing to do with the query, unless the results that you get from your MBO has the value of the Personalization Key that you provided (like a propagatted attribute).

Just to remember some basics, and be on the same page:

The Personalization Keys/Synchronization Parameters, should be mapped to your mbo as a way to retrieve data from your EIS (enterprise information system). Not as a input of a query.

Once you map & load these parameters (PK, SP, or a combination of both) to your MBO and synchronize, (if you mapped correctly) the MBO should fill your data to your Cache group at the Unwired Server, and then to your device, via synchronization group. on the next synchronization, if i am correct, you will have on your device all the data of your previous synchronizations and your new one

Now, when your data is on your device, you can use the queries, but not before a synchronization from the Database.

if it is not understanding/construction then check this part of the code...

Check your first line of code for synchronization... you get the personalization keys from your DB, and i got them from the Personalization Key Class

You---> FirstApp_PersonalizationParameters *pp = [FirstApp_FirstAppDB getPersonalizationParameters];

Me --->FirstApp_PersonalizationParameters *pp = [FirstApp_PersonalizationParameters getPersonalizationParameters]; 

that is the way it worked for me the transient storage

And Try Again...

if your problem persist then i would ask you to share us some paint screens:

-Of your MBOs Definition (The load parameter part, the Attributes return part, and the query part), your Cache group & policies and Synch group & policies.

-Also important, What kind of SUP are you using?

Regards,

Daniel

rakshit_doshi
Active Contributor
0 Kudos

Hi,

This is the correct approach. If you want to query the backend and fetch data based on that data you have to use a personalization key which is a simpler approach and if not you can even write a select query statement and get the data from the backend source by executing the query on the MBO object.

Setting the type of personalization key is of concern.

Client personalization keys are persisted in the local database. Serverpersonalization keys are persisted on the Unwired Server. Transcient personalization keys are not persisted and are lost after the device application terminates.

Always safer to use transcient if you have your search criteria changing rapidly.

Hope this helps,

Thanks,

Former Member
0 Kudos

Hello Rakshit,

thanks for your answer. I'm glad that my approach isn't totally wrong. But there are some issues I got this way.

The first is the storage type of personalization keys. I don't want the keys to be stored on the server, because they are just user input values for a query. But if I set the storage type to 'transient', the use of personalization keys doesnt't have any effect on the queries anymore. Do I have to consider something more with transient PKs in native iOS apps?

Another issue I have is a strange behaviour also with personalization keys. I got those two procedures I explained above ... the first query gets a list of business partners .. works fine with server stored PK.

The next step is to get the details of a business partner, if the user tabs on that item. I set another personalization key the same way as in the first step (with the BP_PARTNERID). Now I execute the query with findAll.

Because the BP_PARTNERID is unique, I expect a list with a single object. But the result is somewhat random. Sometimes a empty list is returned, sometimes a list with a single object. Both results can occure with the same business partner.

Query 1 uses a structure as personalization key with (GpSuchenPk)

- city

- email

- partnerid

Query 2 uses a single personalization key (GpIdPk)

- partnerid

Do I have to call some method, between those two queries with different personalization keys?

Thanks,

Christian