Assume I have 3 different classes, A, B & C. C is designed to have a list of As and Bs.
If load a list of As and Bs and keep them attached, how can I set them as lists in a transient C object and persisting the transient object ?
The problem is that each of As and Bs lists are managed by different PersistenceManagers. So if I try to persist a transient C object with a list of As (attached, managed by a PersistenceManager) and a list of Bs (attached, managed by a second PersistenceManager), I'll get an exception saying that the As and Bs are being managed by a different PersistenceManager.
Is there an efficient way to resolve this instead of having to reload all the lists again by the one PersistenceManager responsible for persisting the C object ?
Related
I am trying to do a simple extract in HFM and I keep getting this error.
"Parent-Child name must be specified for Entity dimension due to value: [Parent Total]
Member found that requires parent name:"
All the members in the extract are valid members, this was verified using a smart view extract
The entity dimension does contain alternate hierarchies, i.e. the member in my extract does have two parents
This extract runs successfully when the expand only selection is selected
This is being done via Workiva-WData
The integration user has this level of access
Any help would be much appreciated.
I have tried running almost every combination of member and expand function available, BASE, ALLMEMBERS, IPARENTS, all result in that error.
I'm trying to get a better understanding of what Rows and Rowsets are used for in PeopleCode? I've read through PeopleBooks and still don't feel like I have a good understanding. I'm looking to get more understanding of these as it pertains to Application Engine programs. Perhaps walking through an example may help. Here are some specific questions I have:
I understand that Rowsets, Row, Record, and Field are used to access component buffer data, but is this still the case for stand alone Application Engine programs run via Process Scheduler?
What would be the need or advantage to using these as opposed to using SQL objects/functions (CreateSQL, SQLExec, etc...)? I often see in AE programs where the CreateRowset object is instantiated and uses a .Fill method with a SQL WHERE Clause and I don't quite understand why a SQL was not used instead.
I've seen in PeopleBooks that a Row object in a component scroll is a row, how does a component scroll relate to the row? I've seen references to rows having different scroll levels, is this just a way of grouping and nesting related data?
After you have instantiated the CreateRowset object, what are typical uses of it in the program afterwards? How would you perform logic (If, Then, Else, etc..) on data retrieved by the rowset, or use it to update data?
I appreciate any insight you can share.
You can still use Rowsets, Rows, Records and fields in stand alone Application Engines. Application Engines do not have component buffer data as they are not running within the context of a component. Therefore to use these items you need to populate them using built-in methods like .fill() on a rowset, or .selectByKey() on a record.
The advantage of using rowsets over SQL is that it makes the CRUD easier. There are built-in methods for selecting, updating, inserting and deleting. Additionally you don't have to worry about making a large number of variables if there were multiple fields like you would with a SQL object. Another advantage is when you do the fill, the data is read into memory, where if you looped through the SQL, the SQL cursor would be open longer. The rowset, row, record and field objects also have a lot of other useful methods such as allowing you to executeEdits (validation) or copy from one rowset\row\record to another.
This question is a bit less clear to me but I'll try and explain. If you have a Page, it would have a level 0 row. It then could have multiple Level 1 rowsets. Under each of those it could have a level 2 rowsets.
Level0
/ \
Level1 Level1
/ \ / \
Level2 Level2 Level2 Level2
If one of your level1 rows had 3 rows, then you would find 3 rows in the Rowset associated with that level1. Not sure I explained this to answer what you need, please clarify if I can provide more info
Typically after I create a rowset, I would loop through it. Access the record on each row, do some processing with it. In the example below, I look through all locked accounts and prefix their description with LOCKED and then updated the database.
.
Local boolean &updateResult;
local integer &i;
local record &lockedAccount;
Local rowset &lockedAccounts;
&lockedAccounts = CreateRowset(RECORD.PSOPRDEFN);
&lockedAccounts.fill("WHERE acctlock = 1");
for &i = 1 to &lockedAccounts.ActiveRowCount
&lockedAccount = &lockedAccounts(&i).PSOPRDEFN;
if left(&lockedAccount.OPRDEFNDESCR.value,6) <> "LOCKED" then
&lockedAccount.OPRDEFNDESCR.value = "LOCKED " | &lockedAccount.OPRDEFNDESCR.value;
&updateResult = &lockedAccount.update();
if not &updateResult then
/* Error handle failed update */
end-if;
end-if;
End-for;
I'm having a problem regarding the scores in my game, My game is about answering questions using jumbled letters and when the player gets one correct answer, the game should add +1 to the game score and move to the next level (which is in the next room) and will generate another question, and keeping your last score which is 1. My problem is, the score just keeps on resetting to a value of 0 when moved into the next room. I want it to continuously add +1 even when I go to the next rooms. Thankyou in advance.
There are many solutions.
1) Set your score controller object as persistent
This is the best, as you don't need to do anything else, and in fact, it's a good rule to have one object as a persistent controller.
2) You can save your score to the file and load it each time this object (that stores the variable) is being created
This requires save\load manipulation, and in some cases (e.g you don't want to have ANY persistent objects) can be better, but I highly doubt.
You are not giving enough details about how are you storing the score value.
That may be cause by many issue in the way you are making the game, so im going to try to give all solutions to all possible scenarios:
1) Storing Score in Object Variable
This way may have two different sub scenarios:
a) Going to Next Room after Right answer
b) Restart the same room
This completly reset the variable on the object because the object is destroyed and then created again initilizing again the variables it hold when the room is created.
For this the solution is simply: set persistent true, you can do it from the form object properties (the interface that pop up when you open a object) or using gml on the create event of the object:
object: CREATE event
persistent = true;
This will make the object even if is repeated on the room created to no to create it again, so the event CREATE will no be never repeated again.
2) Storing the Score in variable of the room using Room Creation Event
In this scenario happeng the same that above, its just a local variable the room but exists only for the room and will only exists during the room until its restarted or leaved.
In this case the best is to transform this variable to a global instance in the following way:
global.points = 0;
And this is the best way to store score for you game.
Just remember no to put it in a create event of a not persistent object or it will be reseted to ZERO everything that object is created.
In that case you can check if the variable exists and then if not initializing it:
if (variable_global_exists("points") == true) {
global.points = 0;
}
Now if you want to save it you need to use file functions which is another question.
I have a data model in which entity A contains references to two other entities, B and C. If either B or C is deleted, I want A to be deleted.
When creating A, it's possible to name either B or C as its parent. Is it also possible to name both B and C as its parents so that if either B or C is deleted, A is also deleted?
In more concrete terms, say search results, a result might have both a category and a region, say a web page about birds in North America. The result is stored with a reference to its category and region. Later, you want to delete the category birds and you want the result also deleted. Likewise, you delete the region North America and want the result deleted.
I hate to go on at such length about such a trivial scenario. But it doesn't seem to be covered in any of the Datastore documentation. What am I missing? Is it a basically flawed data model?
Single-parent limitation:
A child can have only one parent in Datastore. In other words, A can only be a child of B OR C, not both. Of course, a parent can have multiple children, though.
Alternative:
You can use a KeyProperty with repeated=True argument and store many Entity keys on it. In Python, this would be like this:
class A(ndb.Model):
associated_with = ndb.KeyProperty(repeated=True)
some_other_property = ndb.StringProperty()
a_entity = A(
associated_with = [b_key, c_key],
some_other_property = 'any value'
)
a_entity.put()
Automatically triggering deletes:
Datastore doesn't offer this functionality out of the box, but you can mimic it in your application. Just one idea for implementing in Python, for example, you could extend the Model class with your own delete method (haven't tested this code, it's just for illustration):
class A(ndb.Model):
associated_with = ndb.KeyProperty(repeated=True)
some_other_property = ndb.StringProperty()
def delete_ext(entity): # entity object
if entity.associated_with:
for associated in entity.associated_with:
associated.delete()
entity.key.delete()
You may want to wrap all the deletes in a transaction. Beware that a single transaction can operate on up to 25 entity groups.
I've written a Data Extender class and editor extension that properly displays a few additional columns for items as you browse lists in the CME (folders and structure groups). I had to register my class to handle commands like GetList, GetListSearch, GetListUserFavorites, and GetListCheckedOutItems.
What I've noticed is that the code gets run even when a list of say, schemas is loaded for a drop-down list in the CME (like when creating a new component and you get the list of schemas in a drop-down). so, even though my additional data columns aren't needed in that situation, the code is still being executed and it slows things down.
It seems that it's the GetList command called in those situations. So, I can't just skip processing based on the command. So, I started looking at the XML that the class receives for the list and I've noticed when the code is run for the drop-downs, there's a Managed="0" in the XML. For example:
For a Structure Group list: <tcm:ListItems Managed="64" ID="tcm:103-546-4">
For a Folder list: <tcm:ListItems Managed="16" ID="tcm:103-411-2">
But for a Schema list: <tcm:ListItems ID="tcm:0-103-1" Managed="0">
For a drop-down showing keyword values for a category: <tcm:ListItems Managed="0" ID="tcm:103-506-512">
So, can I just use this Managed="0" as a flag to indicate that the list being processed isn't going to show my additional columns and I can just quit processing?
Managed value is representation of what items can be created inside OrganizationItem:
64 means you can create pages
16 means you can create components
10, for example would mean you can create folders (2) + schemas (8)
518 - folders (2) + structure groups (4) + categories (512)
The value is 0 for non organizational items.
Value depends on the item itself (you can't create pages in folder, for example), as well as on security settings you have on publication and organizational item
Unfortunately CME can't offer right now that kind of granularity level to allow you to tell in a data extender where a particular WCF API call is coming from. Our WCF API is not context aware yet. It may change in the future.
Trusting Managed="0" is not a great idea.
The reason for that is the model lists are client cached per filter. In the current design the filter has CM related data and nothing related to the context the request is being fired from.
Typically the client user interface is reusing cached model data whenever is possible. For instance the same model list could be used in the CME dashboard and a drop down control placed into some item view, but with different xml list definitions: the first one will have more columns defined in the list definition than the latter. They are basically different views of the same data.
Therefore you may want to think of different solutions for your problem.
Now... where is the data behind those additional columns is coming from? Is it Tridion CM or a third party provider?
Sometimes the web server caching may provide an acceptable way to improve the response times. But that's the kind of design you should evaluate and decide upon.
I think you would have a more robust solution if you read the ID of the list, and only execute your code for lists of type 2 and 4 (Folders and Structure Groups respectively). but that won't help you with search views etc.
From previous experience and what User978511 says the Managed attribute is an indication of item types that can be created from the context of that list.
Unfortunately that means that the Managed attribute may well be 0 for any user that doesn't have sufficient rights to create items. E.g. check what Managed is in a Structure Group for a user that isn't allowed to create Pages or Structure Groups. It may well be 0 in that case too, meaning it is useless for your situation.
Update
You may be able to reach your goal better by looking at the columns parameter:
context.Parameters["columns"]
In a few tests I've run I get different values, depending on whether I get a list for the main list view, the tree or a drop down list.
543
23
7
Those values are a bit mask of these constants (from Constants.js):
/**
* Defines the column filter.
* Used to specify which attributes should be included in XML list data.
* #enum
*/
Tridion.Constants.ColumnFilter =
{
ID: 1,
ID_AND_TITLE: 3,
DEFAULT: 7,
EXTENDED: 15,
ALLOWED_ACTIONS: 16,
VERSIONS: 32,
INTERNALS: 64,
URL: 128,
XML_NAME: 256,
CHECK_OUT_USER: 512,
PUBTITLE_AND_ITEM_PATH: 1024
};
So from my limited testing it seems that drop downs request DEFAULT columns, while the main list view and the tree both have ALLOWED_ACTIONS in there. This makes sense to me, since the user gets can interact with the list items in the tree and list view, while they can only select them in the drop downs. So checking for the presence of ALLOWED_ACTIONS in the columns parameter might be one way to reduce the number of places where your data extender adds information.