All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.droitateddb.EntityService Maven / Gradle / Ivy

/*
 * Copyright (C) 2014 The droitated DB Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.droitateddb;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import org.droitateddb.cursor.CombinedCursorImpl;
import org.droitateddb.entity.Column;
import org.droitateddb.entity.Entity;
import org.droitateddb.entity.PrimaryKey;
import org.droitateddb.schema.EntityInfo;
import org.droitateddb.validation.AccumulatedValidationResult;
import org.droitateddb.validation.InvalidEntityException;
import org.droitateddb.validation.ValidationToggle;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Provides support for executing CRUD operations on {@link org.droitateddb.entity.Entity} classes, such getting them from the database or
 * saving them to the database.
*
* Each operation opens a connection to the {@link SQLiteDatabase}. If you want only one db connection use * {@link ConnectedEntityService} * * @param Entity, for which this service will be used * @author Falk Appel * @author Alexander Frank */ public class EntityService { private final Context context; private final Class entityClass; private String tableName; private final EntityInfo entityInfo; private Field primaryKey; protected DbCreator dbCreator; private DatabaseValidator databaseValidator; private ValidationToggle toggle; /** * Creates a {@link EntityService} for the given {@link org.droitateddb.entity.Entity}.
* The validation when saving {@link org.droitateddb.entity.Entity}s is turned on. * * @param context Android context * @param entityClass Class of the {@link org.droitateddb.entity.Entity}, the service should be used for * @throws IllegalArgumentException When the given {@link #entityClass} is no {@link org.droitateddb.entity.Entity} */ public EntityService(final Context context, final Class entityClass) { this(context, entityClass, ValidationToggle.ON, DbCreator.getInstance(context)); } /** * Creates a {@link EntityService} for the given {@link org.droitateddb.entity.Entity} * * @param context Android context * @param entityClass Class of the {@link org.droitateddb.entity.Entity}, the service should be used for * @param toggle Controls the use of validation on saving {@link org.droitateddb.entity.Entity}s * @throws IllegalArgumentException When the given {@link #entityClass} is no {@link org.droitateddb.entity.Entity} */ public EntityService(final Context context, final Class entityClass, ValidationToggle toggle) { this(context, entityClass, toggle, DbCreator.getInstance(context)); } /* * Provides test access to constructor */ EntityService(final Context context, final Class entityClass, ValidationToggle toggle, final DbCreator dbCreator) { if (entityClass.getAnnotation(Entity.class) == null) { throw new IllegalArgumentException("The EntityService can only be used for @Entity annotated classes"); } this.context = context; this.entityClass = entityClass; this.entityInfo = SchemaUtil.getEntityInfo(entityClass); this.tableName = SchemaUtil.getTableName(entityClass); this.toggle = toggle; this.dbCreator = dbCreator; this.databaseValidator = new DatabaseValidator(); initColumns(); } private void initColumns() { for (Field field : entityClass.getDeclaredFields()) { if (field.getAnnotation(Column.class) != null) { if (field.getAnnotation(PrimaryKey.class) != null) { primaryKey = field; } } } } /** * Reads all {@link Entity}s of the service specific type from the database * * @return All {@link Entity}s stored in the database, if non are found a empty list is returned */ public List get() { return find(null, null, null); } /** * Gets a specific {@link Entity} according to the given id * * @param id primary key of the {@link Entity} * @return The {@link Entity} to the given id, or null if non was found */ public E get(final long id) { SQLiteDatabase database = openDB(); try { Cursor cursor = database.query(tableName, null, primaryKey.getName() + " = ?", new String[]{Long.toString(id)}, null, null, null); if (cursor.getCount() == 0) { return null; } return CursorOperation.tryOnCursor(cursor, new CursorOperation() { @Override public E execute(final Cursor cursor) { return CombinedCursorImpl.create(context, cursor, entityInfo, entityClass).getCurrent(); } }); } finally { closeDB(database); } } protected void closeDB(SQLiteDatabase database) { dbCreator.reduceDatabaseConnection(); } protected SQLiteDatabase openDB() { return dbCreator.getDatabaseConnection(); } /** * Search for {@link Entity}s in the database with basic SQL WHERE statements. * * @param selection SQL WHERE statement * @param selectionArgs Arguments for the WHERE statement * @param order Sort order of the result * @return All found {@link Entity}s or an empty list of non are found */ public List find(final String selection, final String[] selectionArgs, final String order) { SQLiteDatabase database = openDB(); try { Cursor cursor = database.query(tableName, null, selection, selectionArgs, null, null, order); return CursorOperation.tryOnCursor(cursor, new CursorOperation>() { @Override public List execute(final Cursor cursor) { return new ArrayList(CombinedCursorImpl.create(context, cursor, entityInfo, entityClass).getAll()); } }); } finally { closeDB(database); } } /** * Resolves the associations to a given {@link Entity} object and all underlying associations within the object * graph. * * @param data {@link Entity} on which the associations should be resolved */ public void resolveAssociations(final E data) { SQLiteDatabase database = openDB(); try { new DatabaseResolver(context, database).resolve(data, 0, Integer.MAX_VALUE); } finally { closeDB(database); } } /** * Resolves the associations to a given {@link Entity} object. The associations will only be resolved to the given * depth within the object graph. * * @param data {@link Entity} on which the associations should be resolved * @param maxDepth The maximum depth to which the associations should be resolved */ public void resolveAssociations(final E data, final int maxDepth) { SQLiteDatabase database = openDB(); try { new DatabaseResolver(context, database).resolve(data, 0, maxDepth); } finally { closeDB(database); } } /** * Stores the given {@link Entity} to the database. All attached associations will be stored as well. * * @param data {@link Entity} which should be stored * @return The primary key of the given data. * @throws IllegalStateException When the {@link PrimaryKey} field and its value of the {@link Entity} could * not be determined * @throws org.droitateddb.validation.InvalidEntityException when the given entity is invalid. */ public long save(final E data) { return save(data, Integer.MAX_VALUE); } /** * Stores the given {@link Entity} to the database. Associated objects will be saved to the given maxDepth.
* maxDepth of 0 means that only the given {@link Entity} itself will be saved without associations. * * @param data {@link Entity} which should be stored * @param maxDepth The maximum depth of the associated objects which should also be saved. * @return The primary key of the given data. * @throws IllegalStateException When the {@link PrimaryKey} field and its value of the {@link Entity} could * not be determined * @throws org.droitateddb.validation.InvalidEntityException when the given entity is invalid. */ public long save(final E data, final int maxDepth) { if (toggle == ValidationToggle.ON) { AccumulatedValidationResult validationResult = databaseValidator.validate(data, maxDepth); if (!validationResult.isValid()) { throw new InvalidEntityException(validationResult); } } final SQLiteDatabase database = openDB(); try { return transactional(database, new DatabaseOperation() { @Override public Number execute() { return new DatabaseSaver(database, maxDepth).save(data); } }).longValue(); } finally { closeDB(database); } } /** * Stores all given {@link Entity}s in the {@link Collection} to the database. All attached associations will be * stored as well. * * @param data {@link Entity}s which should be stored * @throws IllegalStateException When the {@link PrimaryKey} field and its value of the {@link Entity} could * not be determined * @throws org.droitateddb.validation.InvalidEntityException when at least one of the given entities is invalid. */ public void save(final Collection data) { save(data, Integer.MAX_VALUE); } /** * Stores all given {@link Entity}s in the {@link Collection} to the database. Associated objects will be saved to * the given maxDepth.
* maxDepth of 0 means that only the given {@link Entity} itself will be saved without associations. * * @param data {@link Entity} which should be stored * @param maxDepth The maximum depth of the associated objects which should also be saved. * @throws IllegalStateException When the {@link PrimaryKey} field and its value of the {@link Entity} could * not be determined * @throws org.droitateddb.validation.InvalidEntityException when at least one of the given entities is invalid. */ public void save(final Collection data, final int maxDepth) { if (toggle == ValidationToggle.ON) { AccumulatedValidationResult validationResult = databaseValidator.validate(data, maxDepth); if (!validationResult.isValid()) { throw new InvalidEntityException(validationResult); } } SQLiteDatabase database = openDB(); try { final DatabaseSaver databaseSaver = new DatabaseSaver(database, maxDepth); transactional(database, new DatabaseOperation() { @Override public Void execute() { for (E object : data) { databaseSaver.save(object); } return null; } }); } finally { closeDB(database); } } /** * Deletes the given {@link Entity} from the database * * @param data {@link Entity} that should be deleted * @return true if the {@link Entity} could be deleted, false otherwise * @throws IllegalStateException When the {@link PrimaryKey} field and its value of the {@link Entity} could not be determined * @throws IllegalArgumentException When the value of the {@link PrimaryKey} field is null */ public boolean delete(final E data) { Number id = (Number) Utilities.getFieldValue(data, primaryKey); if (id == null) { throw new IllegalArgumentException("The @PrimaryKey of the given @Entity can not be null"); } return delete(id.longValue()); } /** * Deletes the data of the {@link Entity} for the given id * * @param id primary key of the {@link Entity} to be deleted * @return true if the {@link Entity} could be deleted, false otherwise */ public boolean delete(final long id) { SQLiteDatabase database = openDB(); try { int delete = database.delete(tableName, EntityData.getEntityData(entityClass).primaryKey.getName() + "= ?", new String[]{Long.toString(id)}); return delete == 1; } finally { closeDB(database); } } private T transactional(SQLiteDatabase database, final DatabaseOperation operation) { database.beginTransaction(); try { T result = operation.execute(); database.setTransactionSuccessful(); return result; } finally { database.endTransaction(); } } private static interface DatabaseOperation { public E execute(); } /** * Will be removed with Version 0.2.0
* Use {@link ConnectedEntityService} if you need only one db connection. */ // TODO:remove with Version 0.2.0 @Deprecated public void close() { } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy