diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java index fcf8c61bd..deb74d963 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorManager.java @@ -254,7 +254,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } @Override - public DocStoreBeanAdapter createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor deploy) { + public DocStoreBeanAdapter createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor deploy) { return docStoreFactory.createAdapter(descriptor, deploy); } @@ -311,8 +311,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap { try { createListeners(); - readEmbeddedDeployment(); readEntityDeploymentInitial(); + readEmbeddedDeployment(); readEntityBeanTable(); readEntityDeploymentAssociations(); readInheritedIdGenerators(); @@ -338,8 +338,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { return asOfTableMap; } catch (RuntimeException e) { - String msg = "Error in deployment"; - logger.error(msg, e); + logger.error("Error in deployment", e); throw e; } } @@ -532,12 +531,17 @@ public class BeanDescriptorManager implements BeanDescriptorMap { } private BeanDescriptor createEmbedded(Class beanClass) { - - DeployBeanInfo info = createDeployBeanInfo(beanClass); - readDeployAssociations(info); + DeployBeanInfo info = getDeploy(beanClass); return new BeanDescriptor(this, info.getDescriptor()); } + /** + * Return the bean deploy info for the given class. + */ + public DeployBeanInfo getDeploy(Class cls) { + return (DeployBeanInfo) deplyInfoMap.get(cls); + } + private void registerBeanDescriptor(BeanDescriptor desc) { descMap.put(desc.getBeanType().getName(), desc); if (desc.isDocStoreMapped()) { @@ -552,13 +556,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { List> embeddedClasses = bootupClasses.getEmbeddables(); for (int i = 0; i < embeddedClasses.size(); i++) { - Class cls = embeddedClasses.get(i); - if (logger.isTraceEnabled()) { - String msg = "load deployinfo for embeddable:" + cls.getName(); - logger.trace(msg); - } - BeanDescriptor embDesc = createEmbedded(cls); - registerBeanDescriptor(embDesc); + registerBeanDescriptor(createEmbedded(embeddedClasses.get(i))); } } @@ -571,12 +569,15 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ private void readEntityDeploymentInitial() { - List> entityClasses = bootupClasses.getEntities(); - - for (Class entityClass : entityClasses) { + for (Class entityClass : bootupClasses.getEntities()) { DeployBeanInfo info = createDeployBeanInfo(entityClass); deplyInfoMap.put(entityClass, info); } + for (Class entityClass : bootupClasses.getEmbeddables()) { + DeployBeanInfo info = createDeployBeanInfo(entityClass); + readDeployAssociations(info); + deplyInfoMap.put(entityClass, info); + } } /** @@ -1075,7 +1076,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap { */ private DeployBeanInfo createDeployBeanInfo(Class beanClass) { - DeployBeanDescriptor desc = new DeployBeanDescriptor(beanClass, serverConfig); + DeployBeanDescriptor desc = new DeployBeanDescriptor(this, beanClass, serverConfig); desc.setUpdateChangesOnly(updateChangesOnly); diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorMap.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorMap.java index 6db829d0b..80b65b6f9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorMap.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptorMap.java @@ -48,5 +48,5 @@ public interface BeanDescriptorMap { /** * Create a doc store specific adapter for this bean type. */ - DocStoreBeanAdapter createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor deploy); + DocStoreBeanAdapter createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor deploy); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java index f3115df82..39ce11026 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java @@ -31,29 +31,29 @@ import java.util.Map; */ public class BeanPropertyAssocOne extends BeanPropertyAssoc { - protected final boolean oneToOne; + private final boolean oneToOne; - protected final boolean oneToOneExported; + private final boolean oneToOneExported; - protected final boolean importedPrimaryKey; + private final boolean importedPrimaryKey; - protected AssocOneHelp localHelp; + private AssocOneHelp localHelp; protected final BeanProperty[] embeddedProps; - protected final HashMap embeddedPropsMap; + private final HashMap embeddedPropsMap; /** * The information for Imported foreign Keys. */ protected ImportedId importedId; - protected ExportedProperty[] exportedProperties; + private ExportedProperty[] exportedProperties; - protected String deleteByParentIdSql; - protected String deleteByParentIdInSql; + private String deleteByParentIdSql; + private String deleteByParentIdInSql; - protected BeanPropertyAssocMany relationshipProperty; + private BeanPropertyAssocMany relationshipProperty; /** * Create based on deploy information of an EmbeddedId. @@ -70,7 +70,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { super(descriptor, deploy); - importedPrimaryKey = false;//TODO: Review this - deploy.isImportedPrimaryKey(); + importedPrimaryKey = deploy.isImportedPrimaryKey(); oneToOne = deploy.isOneToOne(); oneToOneExported = deploy.isOneToOneExported(); @@ -128,21 +128,21 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { return (EntityBean) getValue(owner); } - public void setRelationshipProperty(BeanPropertyAssocMany relationshipProperty) { + void setRelationshipProperty(BeanPropertyAssocMany relationshipProperty) { this.relationshipProperty = relationshipProperty; } - public BeanPropertyAssocMany getRelationshipProperty() { + BeanPropertyAssocMany getRelationshipProperty() { return relationshipProperty; } - public void cacheClear() { + void cacheClear() { if (targetDescriptor.isBeanCaching() && relationshipProperty != null) { targetDescriptor.cacheManyPropClear(relationshipProperty.getName()); } } - public void cacheDelete(boolean clearOnNull, EntityBean bean) { + void cacheDelete(boolean clearOnNull, EntityBean bean) { if (targetDescriptor.isBeanCaching() && relationshipProperty != null) { Object assocBean = getValue(bean); if (assocBean != null) { @@ -269,7 +269,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { } } - public void addFkey() { + void addFkey() { if (importedId != null) { importedId.addFkeys(name); } @@ -593,7 +593,7 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc { /** * Set the owner on the embedded bean property. */ - public void setEmbeddedOwner(EntityBean owner) { + void setEmbeddedOwner(EntityBean owner) { Object emb = getValue(owner); if (emb != null) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java index af34442e8..bbe6d47d9 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java @@ -14,8 +14,10 @@ import com.avaje.ebean.event.BeanPostLoad; import com.avaje.ebean.event.BeanQueryAdapter; import com.avaje.ebean.event.changelog.ChangeLogFilter; import com.avaje.ebean.text.PathProperties; +import com.avaje.ebean.util.CamelCaseHelper; import com.avaje.ebeaninternal.server.core.CacheOptions; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType; +import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager; import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistController; import com.avaje.ebeaninternal.server.deploy.ChainedBeanPersistListener; import com.avaje.ebeaninternal.server.deploy.ChainedBeanPostLoad; @@ -25,6 +27,7 @@ import com.avaje.ebeaninternal.server.deploy.DRawSqlMeta; import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery; import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate; import com.avaje.ebeaninternal.server.deploy.InheritInfo; +import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo; import javax.persistence.Entity; import javax.persistence.MappedSuperclass; @@ -42,7 +45,7 @@ import java.util.Map; */ public class DeployBeanDescriptor { - static class PropOrder implements Comparator { + private static class PropOrder implements Comparator { public int compare(DeployBeanProperty o1, DeployBeanProperty o2) { @@ -58,6 +61,8 @@ public class DeployBeanDescriptor { private final ServerConfig serverConfig; + private final BeanDescriptorManager manager; + /** * Map of BeanProperty Linked so as to preserve order. */ @@ -191,14 +196,24 @@ public class DeployBeanDescriptor { private DocStoreMode docStoreUpdate; private DocStoreMode docStoreDelete; + private List idProperties; + /** * Construct the BeanDescriptor. */ - public DeployBeanDescriptor(Class beanType, ServerConfig serverConfig) { + public DeployBeanDescriptor(BeanDescriptorManager manager, Class beanType, ServerConfig serverConfig) { + this.manager = manager; this.serverConfig = serverConfig; this.beanType = beanType; } + /** + * Return the DeployBeanInfo for the given bean class. + */ + DeployBeanInfo getDeploy(Class cls) { + return manager.getDeploy(cls); + } + /** * Return true if this beanType is an abstract class. */ @@ -274,7 +289,7 @@ public class DeployBeanDescriptor { docStoreUpdate = docStore.update(); docStoreDelete = docStore.delete(); String doc = docStore.doc(); - if (doc != null && doc.length() > 0) { + if (doc.length() > 0) { docStorePathProperties = PathProperties.parse(doc); } } @@ -627,6 +642,34 @@ public class DeployBeanDescriptor { return propMap.put(prop.getName(), prop); } + /** + * Find the matching property for a given property name or dbColumn. + *

+ * This is primarily to find imported primary key columns (ManyToOne that also match the PK). + *

+ */ + DeployBeanProperty findMatch(String propertyName, String dbColumn) { + + DeployBeanProperty prop = propMap.get(propertyName); + if (prop != null) { + return prop; + } + if (dbColumn != null) { + String asCamel = CamelCaseHelper.toCamelFromUnderscore(dbColumn); + prop = propMap.get(asCamel); + if (prop != null) { + return prop; + } + // scan looking for dbColumn match + for (DeployBeanProperty property : propMap.values()) { + if (dbColumn.equals(property.getDbColumn())) { + return property; + } + } + } + return null; + } + /** * Get a BeanProperty by its name. */ @@ -697,7 +740,7 @@ public class DeployBeanDescriptor { /** * Set the DB sequence name. */ - public void setSequenceName(String sequenceName) { + private void setSequenceName(String sequenceName) { this.sequenceName = sequenceName; } @@ -764,7 +807,7 @@ public class DeployBeanDescriptor { tableJoinList.add(join); } - public List getTableJoins() { + List getTableJoins() { return tableJoinList; } @@ -850,15 +893,15 @@ public class DeployBeanDescriptor { */ public List propertiesId() { - ArrayList list = new ArrayList(2); - - for (DeployBeanProperty prop : propMap.values()) { - if (prop.isId()) { - list.add(prop); + if (idProperties == null) { + idProperties = new ArrayList(2); + for (DeployBeanProperty prop : propMap.values()) { + if (prop.isId()) { + idProperties.add(prop); + } } } - - return list; + return idProperties; } public DeployBeanPropertyAssocOne findJoinToTable(String tableName) { diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java index 87ad6b07a..beefce9eb 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanProperty.java @@ -183,7 +183,7 @@ public class DeployBeanProperty { */ private GeneratedProperty generatedProperty; - private final DeployBeanDescriptor desc; + protected final DeployBeanDescriptor desc; private boolean undirectionalShadow; diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java index 2a86d6304..9f823098a 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssoc.java @@ -12,43 +12,50 @@ public abstract class DeployBeanPropertyAssoc extends DeployBeanProperty { /** * The type of the joined bean. */ - Class targetType; + protected Class targetType; /** * Persist settings. */ - final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo(); + private final BeanCascadeInfo cascadeInfo = new BeanCascadeInfo(); /** * The join table information. */ - BeanTable beanTable; + private BeanTable beanTable; /** * Join between the beans. */ - final DeployTableJoin tableJoin = new DeployTableJoin(); + protected final DeployTableJoin tableJoin = new DeployTableJoin(); /** * Literal added to where clause of lazy loading query. */ - String extraWhere; + private String extraWhere; /** * From the deployment mappedBy attribute. */ - String mappedBy; + private String mappedBy; - String docStoreDoc; + private String docStoreDoc; /** * Construct the property. */ - public DeployBeanPropertyAssoc(DeployBeanDescriptor desc, Class targetType) { + DeployBeanPropertyAssoc(DeployBeanDescriptor desc, Class targetType) { super(desc, targetType, null, null); this.targetType = targetType; } + /** + * Return the target DeployBeanDescriptor for this associated bean property. + */ + public DeployBeanDescriptor getTargetDeploy() { + return desc.getDeploy(targetType).getDescriptor(); + } + /** * Return the type of the target. *

diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java index 73b827257..686a3e4f2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyAssocOne.java @@ -5,11 +5,13 @@ package com.avaje.ebeaninternal.server.deploy.meta; */ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { - boolean oneToOne; + private boolean oneToOne; - boolean oneToOneExported; + private boolean oneToOneExported; - DeployBeanEmbedded deployEmbedded; + private boolean importedPrimaryKey; + + private DeployBeanEmbedded deployEmbedded; /** * Create the property. @@ -76,7 +78,22 @@ public class DeployBeanPropertyAssocOne extends DeployBeanPropertyAssoc { this.oneToOneExported = true; } + /** + * Return true if this is part of the primary key. + */ public boolean isImportedPrimaryKey() { - return false; + return importedPrimaryKey; + } + + /** + * Set to true if this is part of the primary key. + */ + void setImportedPrimaryKey(DeployBeanProperty primaryKey) { + this.importedPrimaryKey = true; + String dbColumn = primaryKey.getDbColumn(); + if (dbColumn != null) { + // change join db column if matched by property name + tableJoin.setLocalColumn(dbColumn); + } } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java index 697f13dcd..b0666e501 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanPropertyLists.java @@ -1,12 +1,5 @@ package com.avaje.ebeaninternal.server.deploy.meta; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import com.avaje.ebean.bean.BeanCollection.ModifyListenMode; import com.avaje.ebeaninternal.server.deploy.BeanDescriptor; import com.avaje.ebeaninternal.server.deploy.BeanDescriptorMap; @@ -18,6 +11,12 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertySimpleCollection; import com.avaje.ebeaninternal.server.deploy.InheritInfo; import com.avaje.ebeaninternal.server.deploy.TableJoin; import com.avaje.ebeaninternal.server.type.ScalarTypeString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; /** * Helper object to classify BeanProperties into appropriate lists. @@ -68,6 +67,8 @@ public class DeployBeanPropertyLists { public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor desc, DeployBeanDescriptor deploy) { this.desc = desc; + setImportedPrimaryKeys(deploy); + DeployBeanPropertyAssocOne deployUnidirectional = deploy.getUnidirectional(); if (deployUnidirectional == null) { unidirectional = null; @@ -125,6 +126,31 @@ public class DeployBeanPropertyLists { } } + /** + * Find and set imported primary keys. + *

+ * This is where @ManyToOne properties maps to a PFK (Primary and foreign key). + * Perform the match by naming convention on property name and db column. + *

+ */ + private void setImportedPrimaryKeys(DeployBeanDescriptor deploy) { + + List ids = deploy.propertiesId(); + if (ids.size() == 1) { + DeployBeanProperty id = ids.get(0); + if (id instanceof DeployBeanPropertyAssocOne) { + // only interested if the primary key is a compound key + DeployBeanDescriptor targetDeploy = ((DeployBeanPropertyAssocOne) id).getTargetDeploy(); + for (DeployBeanPropertyAssocOne assoc : deploy.propertiesAssocOne()) { + DeployBeanProperty pkMatch = targetDeploy.findMatch(assoc.getName(), assoc.getDbColumn()); + if (pkMatch != null) { + assoc.setImportedPrimaryKey(pkMatch); + } + } + } + } + } + /** * Return the unidirectional. */ diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoin.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoin.java index 3b003acbd..a6ba48af8 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoin.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoin.java @@ -155,4 +155,13 @@ public class DeployTableJoin { public void setInheritInfo(InheritInfo inheritInfo) { this.inheritInfo = inheritInfo; } + + /** + * Change the join column (based on imported primary key match on property name etc). + */ + void setLocalColumn(String dbColumn) { + if (columns.size() == 1) { + columns.get(0).setLocalDbColumn(dbColumn); + } + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java index 16c03a726..cc2a8ca50 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployTableJoinColumn.java @@ -126,4 +126,10 @@ public class DeployTableJoinColumn { return localDbColumn; } + /** + * Set the local database column name. + */ + public void setLocalDbColumn(String localDbColumn) { + this.localDbColumn = localDbColumn; + } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java index 1fb9a0730..b07be39d2 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java +++ b/src/main/java/com/avaje/ebeaninternal/server/persist/dmlbind/BindableIdEmbedded.java @@ -82,8 +82,8 @@ public final class BindableIdEmbedded implements BindableId { public boolean deriveConcatenatedId(PersistRequestBean persist) { if (matches == null) { - String m = "Matches for the concatinated key columns where not found?" - + " I expect that the concatinated key was null, and this bean does" + String m = "Matches for the concatenated key columns where not found?" + + " I expect that the concatenated key was null, and this bean does" + " not have ManyToOne assoc beans matching the primary key columns?"; throw new PersistenceException(m); }