Advanced Customization > Services and Infrastructure Customization > System Generation > Modeling Business Objects > Specialized Persistence Constructs
  
Specialized Persistence Constructs
GenAsUnPersistable “tables”
All classes recognized as being mapped to database tables must extend wt.fc.Persistable. The GenAsPersistable-generated “_” class automatically handles this for you; the GenAsBinaryLink-generated “_” class achieves this by implementing wt.fc.BinaryLink, which extends Persistable.
When modeling interfaces to be implemented by persistent classes, you will typically use these annotations to describe the columns (properties, foreign keys, and roles) you’ll ultimately want the implementing (concrete) classes to represent as columns. Windchill’s domain interfaces employ this strategy, allowing you to simply implement a bunch of interfaces to acquire important business logic like work-in-progress (Workable) lifecycle management (LifeCycleManaged), and so on.
You must annotate an interface if you want implementing classes to (automatically) persist the interface’s properties. However, not every interface is always intended to be implemented only by persistent classes. In some (exceeding rare) cases, an interface may be implemented by persistent classes (necessitating that the interface be annotated so its data can be persisted) and by non-persistent classes (for which GenAsPersistable and GenAsBinaryLink’s ensuring that the class ends up being Persistable is a problem). In these cases, you can use the GenAsUnPersistable annotation to bridge the gap: any persistent implementer will automatically treat the interface as though it were persistent, while non-persistent implementers won’t get persistence foisted on them.
It should be noted that you’ll likely want your non-persistent classes to be annotated with GenAsUnPersistable to get the same generation benefits as its persistent cousins do, but this is not necessary. Additionally, since externalization logic comes “for free”, you may wish to utilize this annotation in cases where the class is to be “persisted” as a BLOB , since RMI externalization is employed when blobbing instances. Here, “persisted as a BLOB” means that the entire class will be stored in a BLOB column inside a persisted class’s table. BLOBing an object is almost never recommended because it’s easy to overlook the complexities of reading the BLOB back out, especially if the class has changed since the instance was put in. Note that if you wish to store as a BLOB any class implementing wt.fc.NetFactor, you must make that class wt.util.Evolvable.
GenAsEnueratedType columns
Windchill provides support for modeling a discrete, localizable set of strings. Let’s say you want to store computer models in Windchill and wanted to categorize them as being either a desktop, laptop, or server. You could do this as follows:
Listing 12: ComputerType.java
01 package com.acme.example;
02
03 import com.ptc.windchill.annotations.metadata.*;
04
05 @GenAsEnumeratedType
06 public class ComputerType extends _ComputerType {
07 public static final ComputerType DESKTOP = toComputerType("desktop");
08 public static final ComputerType LAPTOP = toComputerType("laptop");
09 public static final ComputerType SERVER = toComputerType("server");
10 }
Listing 13: ComputerTypeRB.rbInfo
01 ResourceInfo.class=wt.tools.resource.EnumResourceInfo
02
03 desktop.value=Desktop
04 desktop.order=10
05
06 laptop.value=Laptop
07 laptop.order=20
08 laptop.defaultValue=true
09
10 server.value=Server
11 server.order=30
You can incorporate this into your Computer class using a GeneratedProperty as follows:
Listing 14: Computer type snippet
01 @GeneratedProperty(name="type", type=ComputerType.class, initialValue="ComputerType.getComputerTypeDefault()",
02 constraints=@PropertyConstraints(upperLimit=20, required=true))
The class follows the general format established previously: an annotated class that extends it’s (generated) “_” class. Classes annotated by GenAsEnumeratedType will ultimately extend wt.fc.EnumeratedType and, as can be seen, a number of methods are generated for you. Among them are to<X>(String) and get<X>Default(), where X is the name of our class (to see a complete listing, invoke javap com.acme.example._ComputerType).
Lines 7-9 (of Listing 12) consist of constant declarations which rely on the toComputerType(...) API to produce instances of the enumerated type. Note that these entries must be present in the corresponding rbInfo file, which is named <X>RB.rbInfo and resides in the same directory. This rbInfo file is of type ResourceInfo.class=wt.tools.resource.EnumResourceInfo and supports both localization and value ordering.
We incorporate this enumerated type as a GeneratedProperty. Note the use of initialValue and the constraints: all computer models must be assigned to one of our three types, and the default type is laptop. Enumerated types are stored (and serialized) as simple strings (in this case, the stored value will be one of desktop, laptop, or server). Since the default upperLimit for strings is fairly large at 200 characters (see JavaDoc for more information), a more reasonable limit is provided.
To build the rbInfo file, run ant -f bin/tools.xml bundle -Dbundle.input=com.acme.example.*. The extension must be “rbInfo”, and is case sensitive. If you neglect the uppercase “I”, the bundle target will ignore your file.
GenAsPrimitiveType columns
If you look at the JavaDoc for wt.fc.EnumeratedType. you will see that EnumeratedType is annotated with GenAsPrimitiveType. Also, the single argument to the annotation is String.class.
The GenAsPrimitiveType annotation is a simple annotation, requiring a single value: the “primitive” type the annotated class reduces to (for persistence and serialization). You will likely never use it, but it exists when you want to build a class (logic) around what is otherwise a pretty boring field. If you do use it, you not only need to specify the type to reduce this class to as part of the annotation, you also need to provide a constructor accepting the primitive type and a <type-in-lower-case>Value() method to return the current value.
For more information, refer to the annotation’s JavaDoc.
GenAsDatastoreSequence database sequences
Windchill, out-of-the-box, will automatically assign part number and document numbers. It does this by employing a database sequence.
Listing 15: MySequence.java
01 package com.acme.example;
02
03 import com.ptc.windchill.annotations.metadata.*;
04
05 @GenAsDatastoreSequence
06 public class MySequence extends _MySequence { }
As before, you need to generate and load the SQL (also, anytime you make a change to an annotated class, you will need to restart the MethodServer). Once completed, you can acquire values as demonstrated (the following example will print “1” and “2”, assuming you’ve not already acquired sequence values):
Listing 16: Acquiring sequence values
01 from com.acme.example import MySequence
02 from wt.fc import PersistenceHelper
03
04 print PersistenceHelper.manager.getNextSequence(MySequence )
05 print PersistenceHelper.manager.getNextSequence(MySequence )
* 
The GenAsDatastoreSequence is one of four GenAsDatastore annotations.