Skip to content

AutoIncrement

Fast ACID NoSQL Application Database edited this page Sep 18, 2019 · 4 revisions
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;
    }

Autoincrement

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

Clone this wiki locally