/** * Returns association of this table with the target table. Will return null if there is no association. * * @param target association of this table and the target table. * @return association of this table with the target table. Will return null if there is no association with target * table and specified type. */ public <A extends Association> A getAssociationForTarget(String target){ Association result = null; for (Association association : associations) { if (association.getTarget().equalsIgnoreCase(target)) { result = association; break; } } return (A) result; }
protected boolean hasAssociation(String table, Class<? extends Association> associationClass){ for (Association association : associations) { if(association.getTarget().equalsIgnoreCase(table) && association.getClass().equals(associationClass)) return true; } return false; }
/** * Returns associations of this table with the target table. It is possible * to have more than one association to a target table if a target table is the same as source. Usually this * happens when tree structures are stored in the same table (category has many categories). * * @param target association of this table and the target table. * @return list of associations of this table with the target table. Will return empty list if none found. * table and specified type. */ public List<Association> getAssociationsForTarget(String target) { List<Association> result = new ArrayList<Association>(); for (Association association : associations) { if (association.getTarget().equalsIgnoreCase(target)) { result.add(association); } } return result; }
/** * Returns association of this table with the target table. Will return null if there is no association. * * @param target association of this table and the target table. * @param associationClass class of association in requested. * @return association of this table with the target table. Will return null if there is no association with target * table and specified type. */ public <A extends Association> A getAssociationForTarget(String target, Class<A> associationClass){ Association result = null; for (Association association : associations) { if (association.getClass().equals(associationClass) && association.getTarget().equalsIgnoreCase(target)) { result = association; break; } } return (A) result; }
/** * Checks if there is association to the target model class., * * @param targetModelClass class of a model that will be checked for association from current model. * @return true if any association exists such that the current model is a source and targetModelClass is a target. */ public boolean isAssociatedTo(Class<? extends Model> targetModelClass) { for (Association association : associations) { Class targetClass = Registry.instance().getModelClass(association.getTarget(), true); if (targetClass != null && targetClass.equals(targetModelClass)) { return true; } } return false; } }
/** * Checks if this model has a named attribute or association whose target has the same name as argument. * Throws <code>IllegalArgumentException</code> in case it does not find either one. * * @param attributeOrAssociation name of attribute or association target. */ protected void checkAttributeOrAssociation(String attributeOrAssociation) { if (!hasAttribute(attributeOrAssociation)) { boolean contains = false; for (Association association : associations) { if (association.getTarget().equalsIgnoreCase(attributeOrAssociation)) { contains = true; break; } } if (!contains) { StringBuilder sb = new StringBuilder().append("Attribute: '").append(attributeOrAssociation) .append("' is not defined in model: '").append(getModelClass()) .append("' and also, did not find an association by the same name, available attributes: ") .append(getAttributeNames()); if (!associations.isEmpty()) { sb.append("\nAvailable associations:\n"); join(sb, associations, "\n"); } throw new IllegalArgumentException(sb.toString()); } } }
private void deleteMany2ManyDeep(List<Many2ManyAssociation> many2ManyAssociations){ List<Model> allMany2ManyChildren = new ArrayList<Model>(); for (Association association : many2ManyAssociations) { String targetTableName = association.getTarget(); Class c = Registry.instance().getModelClass(targetTableName, false); if(c == null){// this model is probably not defined as a class, but the table exists! logger.error("ActiveJDBC WARNING: failed to find a model class for: {}, maybe model is not defined for this table?" + " There might be a risk of running into integrity constrain violation if this model is not defined.", targetTableName); } else{ allMany2ManyChildren.addAll(getAll(c)); } } deleteJoinsForManyToMany(); for (Model model : allMany2ManyChildren) { model.deleteCascade(); } }
private void deleteChildrenDeep(List<? extends Association> childAssociations){ for (Association association : childAssociations) { String targetTableName = association.getTarget(); Class c = Registry.instance().getModelClass(targetTableName, false); if(c == null){// this model is probably not defined as a class, but the table exists! logger.error("ActiveJDBC WARNING: failed to find a model class for: {}, maybe model is not defined for this table?" + " There might be a risk of running into integrity constrain violation if this model is not defined.", targetTableName); } else{ List<Model> dependencies = getAll(c); for (Model model : dependencies) { model.deleteCascade(); } } } }
/** * Sets a parent on this instance. Basically this sets a correct value of a foreign key in a * parent/child relationship. This only works for one to many and polymorphic associations. * The act of setting a parent does not result in saving to a database. * * @param parent potential parent of this instance. Its ID value must not be null. */ public void setParent(Model parent) { if (parent == null || parent.getId() == null) { throw new IllegalArgumentException("parent cannot ne null and parent ID cannot be null"); } List<Association> associations = getMetaModelLocal().getAssociations(); for (Association association : associations) { if (association instanceof BelongsToAssociation && association.getTarget().equals(parent.getMetaModelLocal().getTableName())) { set(((BelongsToAssociation)association).getFkName(), parent.getId()); return; } if(association instanceof BelongsToPolymorphicAssociation && association.getTarget().equals(parent.getMetaModelLocal().getTableName())){ set("parent_id", parent.getId()); set("parent_type", ((BelongsToPolymorphicAssociation)association).getTypeLabel()); return; } } StringBuilder sb = new StringBuilder(); sb.append("Class: ").append(parent.getClass()).append(" is not associated with ").append(this.getClass()) .append(", list of existing associations:\n"); join(sb, getMetaModelLocal().getAssociations(), "\n"); throw new IllegalArgumentException(sb.toString()); }
static void purgeEdges(MetaModel metaModel) { //this is to eliminate side effects of cache on associations. //TODO: Need to write tests for cases; // 1. One to many relationship. Parent and child are cached. // When a new child inserted, the parent.getAll(Child.class) should see that // 2. Many to many. When a new join inserted, updated or deleted, the one.getAll(Other.class) should see the difference. //Purge associated targets List<Association> associations = metaModel.getAssociations(); for(Association association: associations){ QueryCache.instance().purgeTableCache(association.getTarget()); } //Purge edges in case this model represents a join List<String> edges = Registry.instance().getEdges(metaModel.getTableName()); for(String edge: edges){ QueryCache.instance().purgeTableCache(edge); } }