-
Notifications
You must be signed in to change notification settings - Fork 7
Advance Features
CPOrm has some other advance features that make it easier to work with android content providers. Some of the features have already been discussed in the Select and Loader pages.
CPOrm supports syncing code using the androids Sync Adapters. The nice thing is android will schedule a sync to occur when any data changes occur in your database. When syncing information you don't want to make changes to the data letting android schedule the sync again, for this reason making updates in the sync adapter, you must use the CPSync helper to update information in the ORM, this will tell the ORM not to notify android of data changes to be sync.
//Inserts
CPSyncHelper.insert(Context context, ContentProviderClient provider, T... dataModelObjects);
CPSyncHelper.update(Context context, ContentProviderClient provider, T dataModelObject);
CPSyncHelper.updateColumns(Context context, ContentProviderClient provider, T dataModelObject, String... columns);
CPSyncHelper.delete(Context context, ContentProviderClient provider, T dataModelObject)These are all the basic crud operations that can be used when syncing information. You will notice the update has extra method that will allow you to specify columns, this can be helpful if you have columns that should not trigger changes to content providers, causing them to update when a sync occurs. This can sometimes be the case if you have some sync specific columns that is never shown to the user, like a sync time stamp. In addition to specifying the single column to update, you need to flag the column to not notify of changes.
public class User {
@Column(notifyChanges = false)
private Date syncTimeStamp;
}CPOrm supports the creation of views. Views are created like any other table model, with the exception that they must implement the table view interface.
@Table
public class UserRole implements TableView {
@Override
public String getTableViewSql() {
return "SELECT U._ID, U.USER_NAME, R.ROLE_NAME FROM USER U INNER JOIN ROLE R ON U.ROLE_ID = R._ID";
}
@Column
@PrimaryKey
private int _id;
@Column
private String userName;
@Column
private String roleName;
}Another added benefit of using CPOrm is that views can be notified of changes to their underlying data, all you need to do is register a change listener to model objects that the view references.
@Table
@ChangeListeners(changeListeners = UserRole.class)
public class Role extends CPDefaultRecord<Role> {
}
@Table
@ChangeListeners(changeListeners = UserRole.class)
public class User extends CPDefaultRecord<User> {
}CPOrm supports the creation of indexes on tables. Indexes can also be inherited from super classes, so if you have models extending a super class, they will also inherit the creation of the indexes for that model
@Indices(indices =
{
@Index( indexName = "IDX_SYNC_TIMESTAMP", indexColumns = {"sync_timestamp"})
})
public abstract class SyncModel extends CPDefaultRecord<SyncModel> {
@Column
private Date syncTimestamp;
}CPOrm supports the ability for you to create your own column mappings. This allows you to map any java type to any column, and handle the translation of that type to and from the columns. To do this you will need to create your own column type mapping, and register that with the ORM.
Create the Column Mapping.
public class ExampleColumnMapping implements SqlColumnMapping {
@Override
public Class<?> getJavaType() {
return List.class;
}
@Override
public String getSqlColumnTypeName() {
return "BLOB";
}
@Override
public Object toSqlType(Object source) {
ByteArrayOutputStream outputStream = null;
ObjectOutputStream objectOutputStream = null;
try {
outputStream = new ByteArrayOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(source);
objectOutputStream.flush();
return outputStream.toByteArray();
} catch (IOException io) {
Log.e(getClass().getSimpleName(), "Failed to serialize object for storage", io);
return null;
} finally {
closeStreams(outputStream, objectOutputStream);
}
}
@Override
public Object getColumnValue(Cursor cursor, int columnIndex) {
byte[] columnValue = cursor.getBlob(columnIndex);
InputStream inputStream = null;
ObjectInputStream objectInputStream = null;
try{
inputStream = new ByteArrayInputStream(columnValue);
objectInputStream = new ObjectInputStream(inputStream);
return objectInputStream.readObject();
}
catch (Exception ex) {
Log.e(getClass().getSimpleName(), "Failed to deserialize object", ex);
}
finally {
closeStreams(inputStream, objectInputStream);
}
return null;
}
@Override
public void setColumnValue(ContentValues contentValues, String key, Object value) {
contentValues.put(key, (byte[]) toSqlType(value));
}
private void closeStreams(Closeable... streams) {
try {
for (Closeable stream : streams) {
if(stream != null) stream.close();
}
} catch (IOException e) {
Log.e(getClass().getSimpleName(), "Failed to close streams");
}
}
}Now extend the column mapping factory to tell the ORM about our column mappings
public class CustomColumnMapper extends SqlColumnMappingFactory {
private List<SqlColumnMapping> customMappings;
public CustomColumnMapper() {
super();
customMappings = new ArrayList<>();
customMappings.add(new ExampleColumnMapping());
}
@Override
public SqlColumnMapping findColumnMapping(Class<?> fieldType) {
for (SqlColumnMapping customMapping : customMappings) {
Class<?> javaType = customMapping.getJavaType();
if(javaType.equals(fieldType) || javaType.isAssignableFrom(fieldType)) {
return customMapping;
}
}
return super.findColumnMapping(fieldType);
}
}Now register your custom column mapping fatory with the ORM
<meta-data android:name="MAPPING_FACTORY" android:value="za.co.cporm.example.app.mapping.CustomColumnMapper"/>The ORM supports all of the major java primitive types and some extra ones like Date, Calendar and UUID.