Back to project page LitePal.
The source code is released under:
Apache License
If you think the Android project LitePal listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (C) Tony Green, Litepal Framework Open Source Project *//from w ww . j av a2s. c o m * 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.litepal.crud; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import org.litepal.crud.model.AssociationsInfo; import org.litepal.exceptions.DataSupportException; import org.litepal.util.BaseUtility; import org.litepal.util.Const; import org.litepal.util.DBUtility; import android.database.sqlite.SQLiteDatabase; /** * This is a component under DataSupport. It deals with the deleting stuff as * primary task. If deletes a saved model or delete a record with id, the * cascade delete function would work. But considering efficiency, if deletes * with deleteAll method, the referenced data in other tables will not be * affected. Developers should remove those referenced data by their own. * * @author Tony Green * @since 1.1 */ public class DeleteHandler extends DataHandler { /** * To store associated tables of current model's table. Only used while * deleting by id. */ private List<String> foreignKeyTableToDelete; /** * Initialize {@link DataHandler#mDatabase} for operating database. Do not * allow to create instance of DeleteHandler out of CRUD package. * * @param db * The instance of SQLiteDatabase. */ DeleteHandler(SQLiteDatabase db) { mDatabase = db; } /** * The open interface for other classes in CRUD package to delete. Using * baseObj to decide which record to delete. The baseObj must be saved * already(using {@link DataSupport#isSaved()} to test), or nothing will be * deleted. This method can action cascade delete. When the record is * deleted from database, all the referenced data such as foreign key value * will be removed too. * * @param baseObj * The record to delete. * @return The number of rows affected. Including cascade delete rows. */ int onDelete(DataSupport baseObj) { if (baseObj.isSaved()) { analyzeAssociations(baseObj); int rowsAffected = deleteCascade(baseObj); rowsAffected += mDatabase.delete(baseObj.getTableName(), "id = " + baseObj.getBaseObjId(), null); return rowsAffected; } return 0; } /** * The open interface for other classes in CRUD package to delete. Using * modelClass to decide which table to delete from, and id to decide a * specific row. This method can action cascade delete. When the record is * deleted from database, all the referenced data such as foreign key value * will be removed too. * * @param modelClass * Which table to delete from. * @param id * Which record to delete. * @return The number of rows affected. Including cascade delete rows. */ int onDelete(Class<?> modelClass, long id) { analyzeAssociations(modelClass); int rowsAffected = deleteCascade(modelClass, id); rowsAffected += mDatabase.delete(getTableName(modelClass), "id = " + id, null); getForeignKeyTableToDelete().clear(); return rowsAffected; } /** * The open interface for other classes in CRUD package to delete multiple * rows. Using tableName to decide which table to delete from, and * conditions representing the WHERE part of an SQL statement. * * @param tableName * Which table to delete from. * @param conditions * A string array representing the WHERE part of an SQL * statement. * @return The number of rows affected. */ int onDeleteAll(String tableName, String... conditions) { return doDeleteAllAction(tableName, conditions); } /** * Do the action for deleting multiple rows. It will check the validity of * conditions, then delete values in database. If the format of conditions * is invalid, throw DataSupportException. * * @param tableName * Which table to delete from. * @param conditions * A string array representing the WHERE part of an SQL * statement. * @return The number of rows affected. */ private int doDeleteAllAction(String tableName, String... conditions) { BaseUtility.checkConditionsCorrect(conditions); return mDatabase.delete(tableName, getWhereClause(conditions), getWhereArgs(conditions)); } /** * Analyze the associations of modelClass and store the associated tables. * The associated tables might be used when deleting referenced data of a * specified row. * * @param modelClass * To get associations of this class. */ private void analyzeAssociations(Class<?> modelClass) { Collection<AssociationsInfo> associationInfos = getAssociationInfo(modelClass.getName()); for (AssociationsInfo associationInfo : associationInfos) { String associatedTableName = DBUtility.getTableNameByClassName(associationInfo .getAssociatedClassName()); if (associationInfo.getAssociationType() == Const.Model.MANY_TO_ONE || associationInfo.getAssociationType() == Const.Model.ONE_TO_ONE) { String classHoldsForeignKey = associationInfo.getClassHoldsForeignKey(); if (!modelClass.getName().equals(classHoldsForeignKey)) { getForeignKeyTableToDelete().add(associatedTableName); } } else if (associationInfo.getAssociationType() == Const.Model.MANY_TO_MANY) { String joinTableName = DBUtility.getIntermediateTableName(getTableName(modelClass), associatedTableName); joinTableName = BaseUtility.changeCase(joinTableName); getForeignKeyTableToDelete().add(joinTableName); } } } /** * Use the analyzed result of associations to delete referenced data. So * this method must be called after {@link #analyzeAssociations(Class)}. * There're two parts of referenced data to delete. The foreign key rows in * associated table and the foreign key rows in intermediate join table. * * @param modelClass * To get the table name and combine with id as a foreign key * column. * @param id * Delete all the rows which referenced with this id. * @return The number of rows affected in associated tables and intermediate * join tables. */ private int deleteCascade(Class<?> modelClass, long id) { int rowsAffected = 0; for (String associatedTableName : getForeignKeyTableToDelete()) { String fkName = getForeignKeyColumnName(getTableName(modelClass)); rowsAffected += mDatabase.delete(associatedTableName, fkName + " = " + id, null); } return rowsAffected; } /** * Analyze the associations of baseObj and store the result in it. The * associations will be used when deleting referenced data of baseObj. * * @param baseObj * The record to delete. */ private void analyzeAssociations(DataSupport baseObj) { try { Collection<AssociationsInfo> associationInfos = getAssociationInfo(baseObj .getClassName()); analyzeAssociatedModels(baseObj, associationInfos); } catch (Exception e) { throw new DataSupportException(e.getMessage()); } } /** * Use the analyzed result of associations to delete referenced data. So * this method must be called after * {@link #analyzeAssociations(DataSupport)}. There're two parts of * referenced data to delete. The foreign key rows in associated tables and * the foreign key rows in intermediate join tables. * * @param baseObj * The record to delete. Now contains associations info. * @return The number of rows affected in associated table and intermediate * join table. */ private int deleteCascade(DataSupport baseObj) { int rowsAffected; rowsAffected = deleteAssociatedForeignKeyRows(baseObj); rowsAffected += deleteAssociatedJoinTableRows(baseObj); return rowsAffected; } /** * Delete the referenced rows of baseObj in associated tables(Many2One and * One2One conditions). * * @param baseObj * The record to delete. Now contains associations info. * @return The number of rows affected in all associated tables. */ private int deleteAssociatedForeignKeyRows(DataSupport baseObj) { int rowsAffected = 0; Map<String, Set<Long>> associatedModelMap = baseObj.getAssociatedModelsMapWithFK(); for (String associatedTableName : associatedModelMap.keySet()) { String fkName = getForeignKeyColumnName(baseObj.getTableName()); rowsAffected += mDatabase.delete(associatedTableName, fkName + " = " + baseObj.getBaseObjId(), null); } return rowsAffected; } /** * Delete the referenced rows of baseObj in intermediate join * tables(Many2Many condition). * * @param baseObj * The record to delete. Now contains associations info. * @return The number of rows affected in all intermediate join tables. */ private int deleteAssociatedJoinTableRows(DataSupport baseObj) { int rowsAffected = 0; Set<String> associatedTableNames = baseObj.getAssociatedModelsMapForJoinTable().keySet(); for (String associatedTableName : associatedTableNames) { String joinTableName = DBUtility.getIntermediateTableName(baseObj.getTableName(), associatedTableName); String fkName = getForeignKeyColumnName(baseObj.getTableName()); rowsAffected += mDatabase.delete(joinTableName, fkName + " = " + baseObj.getBaseObjId(), null); } return rowsAffected; } /** * Get all the associated tables of current model's table. Only used while * deleting by id. * * @return All the associated tables of current model's table. */ private List<String> getForeignKeyTableToDelete() { if (foreignKeyTableToDelete == null) { foreignKeyTableToDelete = new ArrayList<String>(); } return foreignKeyTableToDelete; } }