// Copyright (c) 2003-present, Jodd Team (http://jodd.org) // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package jodd.db.oom.dao; import jodd.bean.BeanUtil; import jodd.db.DbQuery; import jodd.db.oom.DbEntityDescriptor; import jodd.db.oom.DbOomException; import jodd.db.oom.DbOomManager; import jodd.db.oom.sqlgen.DbEntitySql; import java.util.Collection; import java.util.List; import static jodd.db.oom.DbOomQuery.query; import static jodd.db.oom.sqlgen.DbEntitySql.findByColumn; import static jodd.db.oom.sqlgen.DbEntitySql.insert; /** * Generic DAO. Contains many convenient wrappers. */ public class GenericDao { // ---------------------------------------------------------------- config protected boolean keysGeneratedByDatabase = true; /** * Returns <code>true</code> if keys are auto-generated by database. * Otherwise, keys are generated manually. */ public boolean isKeysGeneratedByDatabase() { return keysGeneratedByDatabase; } /** * Specifies how primary keys are generated. */ public void setKeysGeneratedByDatabase(boolean keysGeneratedByDatabase) { this.keysGeneratedByDatabase = keysGeneratedByDatabase; } // ---------------------------------------------------------------- store /** * Returns <code>true</code> if entity is persistent. */ protected <E> boolean isPersistent(DbEntityDescriptor<E> ded, E entity) { Object key = ded.getIdValue(entity); if (key == null) { return false; } if (key instanceof Number) { long value = ((Number)key).longValue(); if (value == 0) { return false; } } return true; } /** * Sets new ID value for entity. */ protected <E> void setEntityId(DbEntityDescriptor<E> ded, E entity, long newValue) { ded.setIdValue(entity, Long.valueOf(newValue)); } /** * Generates next id for given type. */ protected long generateNextId(DbEntityDescriptor ded) { throw new UnsupportedOperationException("Use Joy"); } /** * Saves or updates entity. If ID is not <code>null</code>, entity will be updated. * Otherwise, entity will be inserted into the database. */ public <E> E store(E entity) { DbOomManager dboom = DbOomManager.getInstance(); Class type = entity.getClass(); DbEntityDescriptor ded = dboom.lookupType(type); if (ded == null) { throw new DbOomException("Not an entity: " + type); } if (!isPersistent(ded, entity)) { DbQuery q; if (keysGeneratedByDatabase) { q = query(insert(entity)); q.setGeneratedKey(); q.executeUpdate(); long nextId = q.getGeneratedKey(); setEntityId(ded, entity, nextId); } else { long nextId = generateNextId(ded); setEntityId(ded, entity, nextId); q = query(insert(entity)); q.executeUpdate(); } q.close(); } else { query(DbEntitySql.updateAll(entity)).autoClose().executeUpdate(); } return entity; } /** * Simply inserts object into the database. */ public void save(Object entity) { DbQuery q = query(insert(entity)); q.autoClose().executeUpdate(); } /** * Inserts bunch of objects into the database. * @see #save(Object) */ public void saveAll(Collection entities) { for (Object entity: entities) { save(entity); } } // ---------------------------------------------------------------- update /** * Updates single entity. */ public void update(Object entity) { query(DbEntitySql.updateAll(entity)).autoClose().executeUpdate(); } /** * Updates all entities. * @see #update(Object) */ public void updateAll(Collection entities) { for (Object entity : entities) { update(entity); } } /** * Updates single property in database and in the bean. */ public <E> E updateProperty(E entity, String name, Object newValue) { query(DbEntitySql.updateColumn(entity, name, newValue)).autoClose().executeUpdate(); BeanUtil.declared.setProperty(entity, name, newValue); return entity; } /** * Updates property in the database by storing the current property value. */ public <E> E updateProperty(E entity, String name) { Object value = BeanUtil.declared.getProperty(entity, name); query(DbEntitySql.updateColumn(entity, name, value)).autoClose().executeUpdate(); return entity; } // ---------------------------------------------------------------- find /** * Finds single entity by its id. */ public <E> E findById(Class<E> entityType, long id) { return query(DbEntitySql.findById(entityType, id)).autoClose().find(entityType); } /** * Finds single entity by matching property. */ public <E> E findOneByProperty(Class<E> entityType, String name, Object value) { return query(findByColumn(entityType, name, value)).autoClose().find(entityType); } /** * Finds one entity for given criteria. */ @SuppressWarnings({"unchecked"}) public <E> E findOne(Object criteria) { return (E) query(DbEntitySql.find(criteria)).autoClose().find(criteria.getClass()); } /** * Finds list of entities matching given criteria. */ @SuppressWarnings({"unchecked"}) public <E> List<E> find(Object criteria) { return query(DbEntitySql.find(criteria)).autoClose().list(criteria.getClass()); } /** * Finds list of entities matching given criteria. */ public <E> List<E> find(Class<E> entityType, Object criteria) { return query(DbEntitySql.find(entityType, criteria)).autoClose().list(entityType); } // ---------------------------------------------------------------- delete /** * Deleted single entity by its id. */ public void deleteById(Class entityType, long id) { query(DbEntitySql.deleteById(entityType, id)).autoClose().executeUpdate(); } /** * Delete single object by its id. Resets ID value. */ public void deleteById(Object entity) { if (entity != null) { int result = query(DbEntitySql.deleteById(entity)).autoClose().executeUpdate(); if (result != 0) { // now reset the ID value DbOomManager dboom = DbOomManager.getInstance(); Class type = entity.getClass(); DbEntityDescriptor ded = dboom.lookupType(type); setEntityId(ded, entity, 0); } } } /** * Deletes all objects by their id. */ public void deleteAllById(Collection objects) { for (Object entity : objects) { deleteById(entity); } } // ---------------------------------------------------------------- count /** * Counts number of all entities. */ public long count(Class entityType) { return query(DbEntitySql.count(entityType)).autoClose().executeCount(); } // ---------------------------------------------------------------- increase /** * Increases a property. */ public void increaseProperty(Class entityType, long id, String name, Number delta) { query(DbEntitySql.increaseColumn(entityType, id, name, delta, true)).autoClose().executeUpdate(); } /** * Decreases a property. */ public void decreaseProperty(Class entityType, long id, String name, Number delta) { query(DbEntitySql.increaseColumn(entityType, id, name, delta, false)).autoClose().executeUpdate(); } // ---------------------------------------------------------------- related /** * Finds related entity. */ public <E> List<E> findRelated(Class<E> target, Object source) { return query(DbEntitySql.findForeign(target, source)).autoClose().list(target); } // ---------------------------------------------------------------- list /** * List all entities. */ public <E> List<E> listAll(Class<E> target) { return query(DbEntitySql.from(target)).autoClose().list(target); } }