#614 - 'Matches for the concatenated key columns where not found' - fix

This commit is contained in:
Robin Bygrave
2016-03-23 17:03:55 +13:00
parent 577dbad9bd
commit 0c4a2d5664
11 changed files with 178 additions and 69 deletions
@@ -254,7 +254,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
}
@Override
public <T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor<T> deploy) {
public <T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor<T> descriptor, DeployBeanDescriptor<T> 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 <T> BeanDescriptor<T> createEmbedded(Class<T> beanClass) {
DeployBeanInfo<T> info = createDeployBeanInfo(beanClass);
readDeployAssociations(info);
DeployBeanInfo<T> info = getDeploy(beanClass);
return new BeanDescriptor<T>(this, info.getDescriptor());
}
/**
* Return the bean deploy info for the given class.
*/
public <T> DeployBeanInfo<T> getDeploy(Class<T> cls) {
return (DeployBeanInfo<T>) 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<Class<?>> 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<Class<?>> 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 <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<T>(beanClass, serverConfig);
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<T>(this, beanClass, serverConfig);
desc.setUpdateChangesOnly(updateChangesOnly);
@@ -48,5 +48,5 @@ public interface BeanDescriptorMap {
/**
* Create a doc store specific adapter for this bean type.
*/
<T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor descriptor, DeployBeanDescriptor<T> deploy);
<T> DocStoreBeanAdapter<T> createDocStoreBeanAdapter(BeanDescriptor<T> descriptor, DeployBeanDescriptor<T> deploy);
}
@@ -31,29 +31,29 @@ import java.util.Map;
*/
public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
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<String, BeanProperty> embeddedPropsMap;
private final HashMap<String, BeanProperty> 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<T> extends BeanPropertyAssoc<T> {
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<T> extends BeanPropertyAssoc<T> {
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<T> extends BeanPropertyAssoc<T> {
}
}
public void addFkey() {
void addFkey() {
if (importedId != null) {
importedId.addFkeys(name);
}
@@ -593,7 +593,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
/**
* Set the owner on the embedded bean property.
*/
public void setEmbeddedOwner(EntityBean owner) {
void setEmbeddedOwner(EntityBean owner) {
Object emb = getValue(owner);
if (emb != null) {
@@ -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<T> {
static class PropOrder implements Comparator<DeployBeanProperty> {
private static class PropOrder implements Comparator<DeployBeanProperty> {
public int compare(DeployBeanProperty o1, DeployBeanProperty o2) {
@@ -58,6 +61,8 @@ public class DeployBeanDescriptor<T> {
private final ServerConfig serverConfig;
private final BeanDescriptorManager manager;
/**
* Map of BeanProperty Linked so as to preserve order.
*/
@@ -191,14 +196,24 @@ public class DeployBeanDescriptor<T> {
private DocStoreMode docStoreUpdate;
private DocStoreMode docStoreDelete;
private List<DeployBeanProperty> idProperties;
/**
* Construct the BeanDescriptor.
*/
public DeployBeanDescriptor(Class<T> beanType, ServerConfig serverConfig) {
public DeployBeanDescriptor(BeanDescriptorManager manager, Class<T> 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<T> {
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<T> {
return propMap.put(prop.getName(), prop);
}
/**
* Find the matching property for a given property name or dbColumn.
* <p>
* This is primarily to find imported primary key columns (ManyToOne that also match the PK).
* </p>
*/
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<T> {
/**
* 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<T> {
tableJoinList.add(join);
}
public List<DeployTableJoin> getTableJoins() {
List<DeployTableJoin> getTableJoins() {
return tableJoinList;
}
@@ -850,15 +893,15 @@ public class DeployBeanDescriptor<T> {
*/
public List<DeployBeanProperty> propertiesId() {
ArrayList<DeployBeanProperty> list = new ArrayList<DeployBeanProperty>(2);
for (DeployBeanProperty prop : propMap.values()) {
if (prop.isId()) {
list.add(prop);
if (idProperties == null) {
idProperties = new ArrayList<DeployBeanProperty>(2);
for (DeployBeanProperty prop : propMap.values()) {
if (prop.isId()) {
idProperties.add(prop);
}
}
}
return list;
return idProperties;
}
public DeployBeanPropertyAssocOne<?> findJoinToTable(String tableName) {
@@ -183,7 +183,7 @@ public class DeployBeanProperty {
*/
private GeneratedProperty generatedProperty;
private final DeployBeanDescriptor<?> desc;
protected final DeployBeanDescriptor<?> desc;
private boolean undirectionalShadow;
@@ -12,43 +12,50 @@ public abstract class DeployBeanPropertyAssoc<T> extends DeployBeanProperty {
/**
* The type of the joined bean.
*/
Class<T> targetType;
protected Class<T> 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<T> targetType) {
DeployBeanPropertyAssoc(DeployBeanDescriptor<?> desc, Class<T> 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.
* <p>
@@ -5,11 +5,13 @@ package com.avaje.ebeaninternal.server.deploy.meta;
*/
public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
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<T> extends DeployBeanPropertyAssoc<T> {
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);
}
}
}
@@ -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.
* <p>
* 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.
* </p>
*/
private void setImportedPrimaryKeys(DeployBeanDescriptor<?> deploy) {
List<DeployBeanProperty> 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.
*/
@@ -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);
}
}
}
@@ -126,4 +126,10 @@ public class DeployTableJoinColumn {
return localDbColumn;
}
/**
* Set the local database column name.
*/
public void setLocalDbColumn(String localDbColumn) {
this.localDbColumn = localDbColumn;
}
}
@@ -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);
}