-
Notifications
You must be signed in to change notification settings - Fork 8
AutoIncrement
package com.db4odoc.disconnectedobj.idexamples;
import com.db4o.ObjectContainer;
import com.db4o.ObjectSet;
import java.util.HashMap;
import java.util.Map;
public class AutoIncrement {
private PersistedAutoIncrements state = null;
private final ObjectContainer container;
public AutoIncrement(ObjectContainer container) {
this.container = container;
}
// #example: getting the next id and storing state
public synchronized int getNextID(Class forClass) {
PersistedAutoIncrements incrementState = ensureLoadedIncrements();
return incrementState.nextNumber(forClass);
}
public synchronized void storeState(){
if(null!=state){
container.ext().store(state,2);
}
}
// #end example
// #example: load the state from the database
private PersistedAutoIncrements ensureLoadedIncrements() {
if(null==state){
state = loadOrCreateState();
}
return state;
}
private PersistedAutoIncrements loadOrCreateState() {
ObjectSet<PersistedAutoIncrements> existingState = container.query(PersistedAutoIncrements.class);
if(0==existingState.size()){
return new PersistedAutoIncrements();
} else if(1==existingState.size()){
return existingState.get(0);
} else{
throw new IllegalStateException("Cannot have more than one state stored in database");
}
}
// #end example
// #example: persistent auto increment
private static class PersistedAutoIncrements {
private final Map<Class, Integer> currentHighestIds = new HashMap<Class, Integer>();
public int nextNumber(Class forClass) {
Integer number = currentHighestIds.get(forClass);
if (null == number) {
number = 0;
}
number += 1;
currentHighestIds.put(forClass,number);
return number;
}
}
// #end example
}
package com.db4odoc.disconnectedobj.idexamples;
import com.db4o.ObjectContainer;
import com.db4o.config.EmbeddedConfiguration;
import com.db4o.events.*;
import com.db4o.foundation.Iterator4;
import com.db4o.internal.LazyObjectReference;
import com.db4o.query.Predicate;
public class AutoIncrementExample implements IdExample<Integer> {
public static IdExample<Integer> create(){
return new AutoIncrementExample();
}
public Integer idForObject(Object obj, ObjectContainer container) {
// #example: get the id
IDHolder idHolder = (IDHolder)obj;
int id = idHolder.getId();
// #end example
return id;
}
public Object objectForID(Integer idForObject, ObjectContainer container) {
final int id = idForObject;
// #example: get an object by its id
Object object = container.query(new Predicate<IDHolder>() {
@Override
public boolean match(IDHolder o) {
return o.getId() == id;
}
}).get(0);
// #end example
return object;
}
public void configure(EmbeddedConfiguration configuration) {
// #example: index the id-field
configuration.common().objectClass(IDHolder.class).objectField("id").indexed(true);
// #end example
}
public void registerEventOnContainer(final ObjectContainer container) {
// #example: use events to assign the ids
final AutoIncrement increment = new AutoIncrement(container);
EventRegistry eventRegistry = EventRegistryFactory.forObjectContainer(container);
eventRegistry.creating().addListener(new EventListener4<CancellableObjectEventArgs>() {
public void onEvent(Event4<CancellableObjectEventArgs> event4,
CancellableObjectEventArgs objectArgs) {
if(objectArgs.object() instanceof IDHolder){
IDHolder idHolder = (IDHolder) objectArgs.object();
//HERE set id
idHolder.setId(increment.getNextID(idHolder.getClass()));
}
}
});
eventRegistry.committing().addListener(new EventListener4<CommitEventArgs>() {
public void onEvent(Event4<CommitEventArgs> commitEventArgsEvent4,
CommitEventArgs commitEventArgs) {
increment.storeState();
}
});
// #end example
}
}
private ObjectContainer openDatabase() {
EmbeddedConfiguration configuration = Db4oEmbedded.newConfiguration();
toRun.configure(configuration);
ObjectContainer container = Db4oEmbedded.openFile(configuration, DATABASE_FILE_NAME);
toRun.registerEventOnContainer(container);
return container;
}
db4o does not deliver a field auto increment feature, which is common in RDBMS. Normally you don't need any additional ids, since db4o manages objects by object-identity. However cases where you have disconnected objects, you need additional ids. One of then possibilities it to use auto incremented ids.
If your application logic requires this feature you can implement it using external callbacks. One of the possible solutions is presented below. Note that this example only works in embedded-mode.
This example assumes that all object which need an auto incremented id are subclasses of the IDHolder class. This class contains the auto-incremented id.
First create a class which keeps the state of the auto-increment numbers. For example a map which keeps the latest auto incremented id for each class.
Then create two methods, which are called later. One which returns the next auto-incremented id for a certain class. Another which stores the current state of the auto-increments.
The last part is to ensure that the existing auto-increments are loaded from the database. Or if not existing a new instance is created.
Now it's time to use the callbacks. Every time when a new object is created, assign a new id. For this the creating-event is perfect. When commiting also make the auto increment-state persistent, to ensure that no id is used twice.
Last, don't forget to index the id-field. Otherwise looks-ups will be slow.
btw, you have Internal-ID and DB4O-UUID inside