For our discussion, we will reuse the data model objects we defined yesterday:
@interface PersonModel : SQLitePersistentObject {
NSString *name;
NSString *nickname;
NSDate *dateOfBirth;
AddressModel *address;
}
@interface AddressModel : SQLitePersistentObject {
NSString *street;
NSString *city;
NSString *state;
NSString *zipCode;
}
1. Querying by Property
When you persist an object using SPO, dynamic class methods are automatically added, allowing you to query by any persisted property. This reduces the amount of SQL code you would have to write, since you no longer need to write your own "SELECT * FROM ..." statements. For example, if we wanted to get a list of all of the people in our database who were named "John Smith", we could write:
NSArray *smiths = [PersonModel findByName@"John Smith"];
That's all there is to it. We can query by any property that is persisted by calling the findByXXX method.
2. Querying by Criteria
What if we wanted to retrive objects using arbitrary criteria? SPO provides methods for that, too. The SQLitePersistentObject class includes a method findByCriteria that allows us to specify our search criteria. For example, to locate all people named "John Smith" that also have the nickname "Johnny", we could write:
NSArray *people = [PersonModel findByCriteria:@"WHERE name = 'John Smith' AND nickname = 'Johnny'"];
We can make this call as simple or as complex as necessary. Include equations, NULL checks, etc. The findFirstByCriteria method works in the same way, however it only returns the first object that matches the search criteria, as opposed to an NSArray of objects.
3. Indices
If we're going to be querying by name, it's important that we define indices so that our SQL queries execute quickly. We can add indices by overriding the indices class method in our data model objects. To add an index for the name property, we would simply write:
+(NSArray *) indices {
NSArray *index1 = [NSArray arrayWithObject:@"name"];
NSArray *indices = [NSArray arrayWithObject:index1];
return indices;
}
This method returns an NSArray comprised of NSArrays that contain the properties that should be used in building the index. Once this is added, our name property will be indexed, and we should see a performance increase when dealing with larger datasets.
4. Transient fields
What if there are properties we do not want persisted? SPO also provides a mechanism for marking properties as transient, thereby not including them within the database. To mark a field as transient, we need to override the transients method in our data model objects. To make the nickname property transient, for example, we would write:
+(NSArray *)transients {
return [NSArray arrayWithObject:@"nickname"];
}
If you examine your database structure after making this change, you will see that the nickname property is no longer stored in the database. This is useful when you wish to make calculations or other values accessible as properties, but want to obtain them at runtime, rather than from the database.
5. Determine if Objects Exist in the Database
The existsInDB method allows us to determine if our data model object has been persisted to the database. For example:
PersonModel *p = [[PersonModel alloc] init];
p.name = @"Joe Blow"
BOOL saved = [p existsInDB]; // Should return NO
[p save];
BOOL savedYet = [p existsInDB]; // Should return YES
This convenience method allows us to determine if our changes have been saved already.
6. Object Deletion
SPO provides 2 methods for deleting objects: deleteObject and deleteObjectCascade. The deleteObjectCascade also allows us to specify whether the child rows associated with the deleted object should also be deleted.
7. Reverting Changes
Often, it is necessary to revert changes that have been made to an object, but not saved to the database yet. SPO provides us with 3 methods for performing an "undo", of sorts. These are: revert, revertProperty, and revertProperties. The revert method will revert all changes made to an objects since the last save to the database. The revertProperty and revertProperties allow us to revert changes to one or more properties, respectively, by name.
This concludes our 2-part introductory lesson on SQLitePersistentObjects. If the rumors are true, iPhone 3.0 will include support for CoreData for data persistence, so it remains to be seen how much of this will be necessary once most users move to iPhone 3.0. In the meantime, however, these tips should help you get your application developed quicker and with far fewer headaches.
Thanks for article.
ReplyDeleteHave a question - does SPO support migrations? Is there an easy way to change database structure from version to version?
@Valerii Hiora
ReplyDeleteI'm not entirely sure, actually. I would imagine that if the change is minor (adding/removing a column/field, etc.) then the schema would be updated. As far as migrations, you would have to pose that question to the developer.