mercredi 5 octobre 2016

How can I update 1:N collections with OrmLite when I add or remove an entity on both sides?

I am using OrmLite Version 4.48. For a reason I like to 1.) ensure that I have for each entity exactly one object at runtime in my application. Also 2.) I do not like to load views with a long delay. Both issues are solved currently by my ObjectCache implementation as shown bellow, which has not yet been broken in my application.

Anyways if I change my Collections:

@ForeignCollectionField(eager = true, foreignFieldName="entity_name", maxEagerLevel=4)

than I usually create a new entity at the 1 side and persist it. In the method, which assigns the N-side object to the 1 side object I usually clear my Cache for all N-side-objects in order to ensure that the ForeignCollections get updated and reinitialized propperly.

But this leads to breaking of my requirement 1.) from above. So maybe instead of clearing my cache I can update the ForeignCollection of my old object on the n-side and also for my new object on the n-side.

But how to do that propperly with OrmLite? How does OrmLite react if I change the collections, which use the annotation posted above and also update my entity with the dao?

public class GlobalHashMapObjectCache implements ObjectCache
{

    private static final boolean debug = false;

    private final static Map<AbstractProjectManager, GlobalHashMapObjectCache> INSTANCES = new HashMap<AbstractProjectManager, GlobalHashMapObjectCache>();
    public static GlobalHashMapObjectCache getInstance( AbstractProjectManager projectManager ){
        if(!INSTANCES.containsKey(projectManager)){
            INSTANCES.put(projectManager, new GlobalHashMapObjectCache());
        }
        return INSTANCES.get(projectManager);
    }
    public static GlobalHashMapObjectCache getInstance(){
        return getInstance( IGlobalProjectManager.PROJECT_MANAGER );
    }

    private GlobalHashMapObjectCache(){}


    private final ConcurrentHashMap<Class<?>, Map<Object, Object>> classMaps =
            new ConcurrentHashMap<Class<?>, Map<Object, Object>>();

    private Collection<Class> noCacheClasses = new LinkedList<>();

    @Override
    public <T, ID> T updateId(Class<T> clazz, ID oldId, ID newId) {
        Map<Object, Object> objectMap = getMapForClass(clazz);
        if (objectMap == null) {
            return null;
        }
        Object entity = objectMap.remove(oldId);
        if (entity == null) {
            return null;
        }
        objectMap.put(newId, entity);

        return (T)entity;   
    }

    @Override
    public int sizeAll() {
        int size = 0;
        for (Map<Object, Object> objectMap : classMaps.values()) {
            size += objectMap.size();
        }
        return size;
    }

    @Override
    public <T> int size(Class<T> clazz) {
        Map<Object, Object> objectMap = getMapForClass(clazz);
        if (objectMap == null) {
            return 0;
        } else {
            return objectMap.size();
        }
    }

    @Override
    public <T, ID> void remove(Class<T> clazz, ID id) {
        synchronized (GlobalHashMapObjectCache.class) {
            Map<Object, Object> objectMap = getMapForClass(clazz);
            if (objectMap != null) {
                objectMap.remove(id);
            }
        }
    }

    @Override
    public <T> void registerClass(Class<T> clazz) {
        synchronized (GlobalHashMapObjectCache.class) {
            if (!classMaps.contains(clazz)) {
                classMaps.put(clazz, new ConcurrentHashMap<Object, Object>());
            }
        }
    }

    @Override
    public <T, ID> void put(Class<T> clazz, ID id, T data) {
        synchronized (GlobalHashMapObjectCache.class) {
            if(noCacheClasses.contains(clazz)){
                return;
            }
            if(debug){
                System.out.println("put " + clazz.toString() + " id:" + id + " → " + data);
            }
            Map<Object, Object> objectMap = getMapForClass(clazz);
            objectMap.put(id, data);
        }
    }

    @Override
    public <T, ID> T get(Class<T> clazz, ID id) {
        synchronized (GlobalHashMapObjectCache.class) {
            Map<Object, Object> objectMap = getMapForClass(clazz);
            if(debug){
                System.out.println("get: " + clazz.toString() + " id:" + id + "→ " + (T)objectMap.get(id));
            }
            return (T)objectMap.get(id);
        }
    }

    @Override
    public void clearAll() {
        synchronized (GlobalHashMapObjectCache.class) {
            for (Map<Object, Object> objectMap : classMaps.values()) {
                objectMap.clear();
            }
        }
    }

    @Override
    public <T> void clear(Class<T> clazz) {
        synchronized (GlobalHashMapObjectCache.class) {
            Map<Object, Object> objectMap = getMapForClass(clazz);
            if (objectMap != null) {
                objectMap.clear();
            }
        }
    }
    private Map<Object, Object> getMapForClass(Class<?> clazz) {
        Map<Object, Object> ret = classMaps.get(clazz);
        if(ret == null){
            registerClass(clazz);
            ret = classMaps.get(clazz);
        }
        return ret;
    }

    public void addNoCacheClass( Class clazz ){
        noCacheClasses.add(clazz);
    }
}

Aucun commentaire:

Enregistrer un commentaire