mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-11-10 00:44:15 +00:00
#225 - Mapping - Add / review support for @IdClass
This commit is contained in:
1 parent
602a35d0b6
commit
4799c56e25
34 files changed
+765
-309
No files matched your search
@@ -133,6 +133,20 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
this.nodeUsageCollector = usageCollector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ownerId (IdClass).
|
||||
*/
|
||||
public Object getOwnerId() {
|
||||
return ownerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ownerId (IdClass).
|
||||
*/
|
||||
public void setOwnerId(Object ownerId) {
|
||||
this.ownerId = ownerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the owning bean for an embedded bean.
|
||||
*/
|
||||
|
||||
@@ -1350,7 +1350,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// already assigned (So custom or UUID)
|
||||
return;
|
||||
}
|
||||
if (desc.propertiesId().isEmpty()) {
|
||||
if (desc.idProperty() == null) {
|
||||
// bean doesn't have an Id property
|
||||
if (desc.isBaseTableType() && desc.getBeanFinder() == null) {
|
||||
// expecting an id property
|
||||
@@ -1491,6 +1491,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private boolean isPersistentField(DeployBeanProperty prop) {
|
||||
|
||||
Field field = prop.getField();
|
||||
if (field == null) {
|
||||
return false;
|
||||
}
|
||||
int modifiers = field.getModifiers();
|
||||
return !(Modifier.isStatic(modifiers) || Modifier.isTransient(modifiers)) && !field.isAnnotationPresent(Transient.class);
|
||||
}
|
||||
|
||||
@@ -61,10 +61,12 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanProperty.class);
|
||||
|
||||
/**
|
||||
* Flag to mark this at part of the unique id.
|
||||
* Flag to mark this is the id property.
|
||||
*/
|
||||
final boolean id;
|
||||
|
||||
final boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* Flag to make this as a dummy property for unidirecitonal relationships.
|
||||
*/
|
||||
@@ -274,6 +276,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty
|
||||
this.name = InternString.intern(deploy.getName());
|
||||
this.propertyIndex = deploy.getPropertyIndex();
|
||||
this.unidirectionalShadow = deploy.isUndirectionalShadow();
|
||||
this.importedPrimaryKey = deploy.isImportedPrimaryKey();
|
||||
this.discriminator = deploy.isDiscriminator();
|
||||
this.localEncrypted = deploy.isLocalEncrypted();
|
||||
this.dbEncrypted = deploy.isDbEncrypted();
|
||||
@@ -395,6 +398,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty
|
||||
this.softDeleteDbSet = source.softDeleteDbSet;
|
||||
this.softDeleteDbPredicate = source.softDeleteDbPredicate;
|
||||
this.fetchEager = source.fetchEager;
|
||||
this.importedPrimaryKey = source.importedPrimaryKey;
|
||||
this.unidirectionalShadow = source.unidirectionalShadow;
|
||||
this.discriminator = source.discriminator;
|
||||
this.localEncrypted = source.isLocalEncrypted();
|
||||
@@ -473,8 +477,7 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty
|
||||
this.deployOrder = deployOrder;
|
||||
}
|
||||
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain,
|
||||
boolean propertyDeploy) {
|
||||
public ElPropertyValue buildElPropertyValue(String propName, String remainder, ElPropertyChainBuilder chain, boolean propertyDeploy) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -935,6 +938,13 @@ public class BeanProperty implements ElPropertyValue, Property, SqlTreeProperty
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true this bean maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAssocMany() {
|
||||
// Returns false - override in BeanPropertyAssocMany.
|
||||
|
||||
@@ -40,8 +40,6 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
private final boolean orphanRemoval;
|
||||
|
||||
private final boolean importedPrimaryKey;
|
||||
|
||||
private final boolean primaryKeyExport;
|
||||
|
||||
private final PropertyForeignKey foreignKey;
|
||||
@@ -76,7 +74,6 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
foreignKey = deploy.getForeignKey();
|
||||
primaryKeyExport = deploy.isPrimaryKeyExport();
|
||||
importedPrimaryKey = deploy.isImportedPrimaryKey();
|
||||
oneToOne = deploy.isOneToOne();
|
||||
oneToOneExported = deploy.isOneToOneExported();
|
||||
orphanRemoval = deploy.isOrphanRemoval();
|
||||
@@ -346,13 +343,6 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
return orphanRemoval;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true this bean maps to the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void diff(String prefix, Map<String, ValuePair> map, EntityBean newBean, EntityBean oldBean) {
|
||||
|
||||
@@ -626,6 +616,14 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
super.setValueIntercept(bean, value);
|
||||
if (embedded && value instanceof EntityBean) {
|
||||
setEmbeddedOwner(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For embedded bean set the owner and all properties to be loaded (recursively).
|
||||
*/
|
||||
@@ -638,18 +636,10 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
private void setEmbeddedOwner(EntityBean bean, Object value) {
|
||||
void setEmbeddedOwner(EntityBean bean, Object value) {
|
||||
((EntityBean) value)._ebean_getIntercept().setEmbeddedOwner(bean, propertyIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
super.setValueIntercept(bean, value);
|
||||
if (embedded && value instanceof EntityBean) {
|
||||
setEmbeddedOwner(bean, value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadIgnore(DbReadContext ctx) {
|
||||
localHelp.loadIgnore(ctx);
|
||||
@@ -708,10 +698,10 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
if (embedded) {
|
||||
writeJson.writeFieldName(name);
|
||||
BeanDescriptor<?> refDesc = descriptor.getBeanDescriptor(value.getClass());
|
||||
refDesc.jsonWriteForInsert(writeJson, (EntityBean)value);
|
||||
refDesc.jsonWriteForInsert(writeJson, (EntityBean) value);
|
||||
|
||||
} else {
|
||||
jsonWriteTargetId(writeJson, (EntityBean)value);
|
||||
jsonWriteTargetId(writeJson, (EntityBean) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebeaninternal.server.deploy;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Bean property for an IdClass embeddedId.
|
||||
*/
|
||||
public class BeanPropertyIdClass extends BeanPropertyAssocOne {
|
||||
|
||||
public BeanPropertyIdClass(BeanDescriptorMap owner, BeanDescriptor descriptor, DeployBeanPropertyAssocOne deploy) {
|
||||
super(owner, descriptor, deploy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(EntityBean bean, Object value) {
|
||||
bean._ebean_getIntercept().setOwnerId(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueIntercept(EntityBean bean, Object value) {
|
||||
bean._ebean_getIntercept().setOwnerId(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(EntityBean bean) {
|
||||
return bean._ebean_getIntercept().getOwnerId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueIntercept(EntityBean bean) {
|
||||
return bean._ebean_getIntercept().getOwnerId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class BeanTable {
|
||||
*/
|
||||
private final String baseTable;
|
||||
|
||||
private final BeanProperty[] idProperties;
|
||||
private final BeanProperty idProperty;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
@@ -39,7 +39,7 @@ public class BeanTable {
|
||||
this.owner = owner;
|
||||
this.beanType = mutable.getBeanType();
|
||||
this.baseTable = InternString.intern(mutable.getBaseTable());
|
||||
this.idProperties = mutable.createIdProperties(owner);
|
||||
this.idProperty = mutable.createIdProperty(owner);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,8 +69,8 @@ public class BeanTable {
|
||||
/**
|
||||
* Return the Id properties.
|
||||
*/
|
||||
public BeanProperty[] getIdProperties() {
|
||||
return idProperties;
|
||||
public BeanProperty getIdProperty() {
|
||||
return idProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,52 +82,51 @@ public class BeanTable {
|
||||
|
||||
public void createJoinColumn(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect) {
|
||||
|
||||
boolean complexKey = false;
|
||||
BeanProperty[] props = idProperties;
|
||||
|
||||
if (idProperties.length == 1) {
|
||||
if (idProperties[0] instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) idProperties[0];
|
||||
props = assocOne.getProperties();
|
||||
complexKey = true;
|
||||
}
|
||||
if (idProperty == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
if (idProperty instanceof BeanPropertyAssocOne<?>) {
|
||||
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) idProperty;
|
||||
BeanProperty[] props = assocOne.getProperties();
|
||||
for (BeanProperty prop : props) {
|
||||
addToJoin(foreignKeyPrefix, join, reverse, sqlFormulaSelect, true, prop);
|
||||
}
|
||||
} else {
|
||||
addToJoin(foreignKeyPrefix, join, reverse, sqlFormulaSelect, false, idProperty);
|
||||
}
|
||||
}
|
||||
|
||||
String lc = prop.getDbColumn();
|
||||
String fk = lc;
|
||||
if (foreignKeyPrefix != null) {
|
||||
fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk);
|
||||
}
|
||||
private void addToJoin(String foreignKeyPrefix, DeployTableJoin join, boolean reverse, String sqlFormulaSelect, boolean complexKey, BeanProperty prop) {
|
||||
|
||||
if (complexKey) {
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
logger.debug("On table[{}] foreign key column [{}]", baseTable, lc);
|
||||
fk = lc;
|
||||
}
|
||||
if (sqlFormulaSelect != null) {
|
||||
fk = sqlFormulaSelect;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
joinCol.setForeignSqlFormula(sqlFormulaSelect);
|
||||
if (reverse) {
|
||||
joinCol = joinCol.reverse();
|
||||
}
|
||||
join.addJoinColumn(joinCol);
|
||||
String lc = prop.getDbColumn();
|
||||
String fk = lc;
|
||||
if (foreignKeyPrefix != null) {
|
||||
fk = owner.getNamingConvention().getForeignKey(foreignKeyPrefix, fk);
|
||||
}
|
||||
|
||||
if (complexKey) {
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
logger.debug("On table[{}] foreign key column [{}]", baseTable, lc);
|
||||
fk = lc;
|
||||
}
|
||||
if (sqlFormulaSelect != null) {
|
||||
fk = sqlFormulaSelect;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
joinCol.setForeignSqlFormula(sqlFormulaSelect);
|
||||
if (reverse) {
|
||||
joinCol = joinCol.reverse();
|
||||
}
|
||||
join.addJoinColumn(joinCol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary key DB column.
|
||||
*/
|
||||
public String getIdColumn() {
|
||||
if (idProperties.length != 1) {
|
||||
throw new IllegalStateException("Expecting only one Id column to join to on "+beanType);
|
||||
}
|
||||
return idProperties[0].dbColumn;
|
||||
return idProperty.dbColumn;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import io.ebean.event.BeanPostLoad;
|
||||
import io.ebean.event.BeanQueryAdapter;
|
||||
import io.ebean.event.changelog.ChangeLogFilter;
|
||||
import io.ebean.text.PathProperties;
|
||||
import io.ebean.util.CamelCaseHelper;
|
||||
import io.ebeaninternal.api.ConcurrencyMode;
|
||||
import io.ebeaninternal.server.core.CacheOptions;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
@@ -91,6 +90,10 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
private IdType idType;
|
||||
|
||||
private Class<?> idClass;
|
||||
|
||||
private DeployBeanPropertyAssocOne<?> idClassProperty;
|
||||
|
||||
/**
|
||||
* Set to true if the identity is default for the platform.
|
||||
*/
|
||||
@@ -205,7 +208,7 @@ public class DeployBeanDescriptor<T> {
|
||||
private DocStoreMode docStoreUpdate;
|
||||
private DocStoreMode docStoreDelete;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
private DeployBeanProperty idProperty;
|
||||
private TableJoin primaryKeyJoin;
|
||||
|
||||
private short profileId;
|
||||
@@ -219,6 +222,20 @@ public class DeployBeanDescriptor<T> {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the IdClass to use.
|
||||
*/
|
||||
public void setIdClass(Class idClass) {
|
||||
this.idClass = idClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is a IdClass set.
|
||||
*/
|
||||
public boolean isIdClass() {
|
||||
return idClass != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* PK is also a FK.
|
||||
*/
|
||||
@@ -335,7 +352,7 @@ public class DeployBeanDescriptor<T> {
|
||||
|
||||
DeployBeanTable beanTable = new DeployBeanTable(getBeanType());
|
||||
beanTable.setBaseTable(baseTable);
|
||||
beanTable.setIdProperties(propertiesId());
|
||||
beanTable.setIdProperty(idProperty());
|
||||
|
||||
return beanTable;
|
||||
}
|
||||
@@ -443,6 +460,10 @@ public class DeployBeanDescriptor<T> {
|
||||
return cacheOptions;
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> getIdClassProperty() {
|
||||
return idClassProperty;
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> getUnidirectional() {
|
||||
return unidirectional;
|
||||
}
|
||||
@@ -684,6 +705,15 @@ public class DeployBeanDescriptor<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public void postAnnotations() {
|
||||
if (idClass != null) {
|
||||
idClassProperty = new DeployBeanPropertyAssocOne<>(this, idClass);
|
||||
idClassProperty.setName("_idClass");
|
||||
idClassProperty.setEmbedded();
|
||||
idClassProperty.setNullable(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a bean property.
|
||||
*/
|
||||
@@ -691,32 +721,8 @@ 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;
|
||||
public Collection<DeployBeanProperty> properties() {
|
||||
return propMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -935,16 +941,14 @@ public class DeployBeanDescriptor<T> {
|
||||
*/
|
||||
public boolean isPrimaryKeyCompoundOrNonNumeric() {
|
||||
|
||||
List<DeployBeanProperty> ids = propertiesId();
|
||||
if (ids.size() != 1) {
|
||||
// compound key
|
||||
return true;
|
||||
DeployBeanProperty id = idProperty();
|
||||
if (id == null) {
|
||||
return false;
|
||||
}
|
||||
DeployBeanProperty p = ids.get(0);
|
||||
if (p instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
return ((DeployBeanPropertyAssocOne<?>) p).isCompound();
|
||||
if (id instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
return ((DeployBeanPropertyAssocOne<?>) id).isCompound();
|
||||
} else {
|
||||
return !p.isDbNumberType();
|
||||
return !id.isDbNumberType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -953,37 +957,32 @@ public class DeployBeanDescriptor<T> {
|
||||
* compound). This is for the purpose of defining a sequence name.
|
||||
*/
|
||||
public String getSinglePrimaryKeyColumn() {
|
||||
List<DeployBeanProperty> ids = propertiesId();
|
||||
if (ids.size() == 1) {
|
||||
DeployBeanProperty p = ids.get(0);
|
||||
if (p instanceof DeployBeanPropertyAssoc<?>) {
|
||||
DeployBeanProperty id = idProperty();
|
||||
if (id != null) {
|
||||
if (id instanceof DeployBeanPropertyAssoc<?>) {
|
||||
// its a compound primary key
|
||||
return null;
|
||||
} else {
|
||||
return p.getDbColumn();
|
||||
return id.getDbColumn();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BeanProperty that make up the unique id.
|
||||
* <p>
|
||||
* The order of these properties can be relied on to be consistent if the bean
|
||||
* itself doesn't change or the xml deployment order does not change.
|
||||
* </p>
|
||||
* Return the BeanProperty that is the Id.
|
||||
*/
|
||||
public List<DeployBeanProperty> propertiesId() {
|
||||
|
||||
if (idProperties == null) {
|
||||
idProperties = new ArrayList<>(2);
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isId()) {
|
||||
idProperties.add(prop);
|
||||
}
|
||||
public DeployBeanProperty idProperty() {
|
||||
if (idProperty != null) {
|
||||
return idProperty;
|
||||
}
|
||||
for (DeployBeanProperty prop : propMap.values()) {
|
||||
if (prop.isId()) {
|
||||
idProperty = prop;
|
||||
return idProperty;
|
||||
}
|
||||
}
|
||||
return idProperties;
|
||||
return null;
|
||||
}
|
||||
|
||||
public DeployBeanPropertyAssocOne<?> findJoinToTable(String tableName) {
|
||||
|
||||
@@ -51,6 +51,7 @@ public class DeployBeanProperty {
|
||||
private static final int AUDITCOLUMN_ORDER = -1000000;
|
||||
private static final int VERSIONCOLUMN_ORDER = -1000000;
|
||||
private static final Set<Class<?>> PRIMITIVE_NUMBER_TYPES = new HashSet<>();
|
||||
|
||||
static {
|
||||
PRIMITIVE_NUMBER_TYPES.add(float.class);
|
||||
PRIMITIVE_NUMBER_TYPES.add(double.class);
|
||||
@@ -64,6 +65,8 @@ public class DeployBeanProperty {
|
||||
*/
|
||||
private boolean id;
|
||||
|
||||
boolean importedPrimaryKey;
|
||||
|
||||
/**
|
||||
* Flag to mark the property as embedded. This could be on
|
||||
* BeanPropertyAssocOne rather than here. Put it here for checking Id type
|
||||
@@ -611,6 +614,16 @@ public class DeployBeanProperty {
|
||||
this.dbUpdateable = false;
|
||||
}
|
||||
|
||||
public void setImportedPrimaryKey() {
|
||||
this.importedPrimaryKey = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is part of the primary key.
|
||||
*/
|
||||
public void setImportedPrimaryKeyColumn(DeployBeanProperty primaryKey) {
|
||||
this.importedPrimaryKey = true;
|
||||
}
|
||||
|
||||
public boolean isAggregation() {
|
||||
return aggregation != null;
|
||||
@@ -889,6 +902,13 @@ public class DeployBeanProperty {
|
||||
return genericType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is part of the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is included in the unique id.
|
||||
*/
|
||||
@@ -1046,6 +1066,10 @@ public class DeployBeanProperty {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public boolean isIdClass() {
|
||||
return desc.isIdClass();
|
||||
}
|
||||
|
||||
public void addDbMigrationInfo(DbMigrationInfo info) {
|
||||
if (dbMigrationInfos == null) {
|
||||
dbMigrationInfos = new ArrayList<>();
|
||||
|
||||
@@ -17,8 +17,6 @@ public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
|
||||
private boolean primaryKeyExport;
|
||||
|
||||
private boolean importedPrimaryKey;
|
||||
|
||||
private DeployBeanEmbedded deployEmbedded;
|
||||
|
||||
private String columnPrefix;
|
||||
@@ -92,17 +90,11 @@ public class DeployBeanPropertyAssocOne<T> extends DeployBeanPropertyAssoc<T> {
|
||||
this.oneToOneExported = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this is part of the primary key.
|
||||
*/
|
||||
public boolean isImportedPrimaryKey() {
|
||||
return importedPrimaryKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if this is part of the primary key.
|
||||
*/
|
||||
void setImportedPrimaryKey(DeployBeanProperty primaryKey) {
|
||||
@Override
|
||||
public void setImportedPrimaryKeyColumn(DeployBeanProperty primaryKey) {
|
||||
this.importedPrimaryKey = true;
|
||||
String dbColumn = primaryKey.getDbColumn();
|
||||
if (dbColumn != null) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyIdClass;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyOrderColumn;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertySimpleCollection;
|
||||
import io.ebeaninternal.server.deploy.InheritInfo;
|
||||
@@ -39,7 +40,7 @@ public class DeployBeanPropertyLists {
|
||||
|
||||
private final LinkedHashMap<String, BeanProperty> propertyMap;
|
||||
|
||||
private final List<BeanProperty> ids = new ArrayList<>();
|
||||
private BeanProperty id;
|
||||
|
||||
private final List<BeanProperty> local = new ArrayList<>();
|
||||
|
||||
@@ -70,7 +71,13 @@ public class DeployBeanPropertyLists {
|
||||
public DeployBeanPropertyLists(BeanDescriptorMap owner, BeanDescriptor<?> desc, DeployBeanDescriptor<?> deploy) {
|
||||
this.desc = desc;
|
||||
|
||||
setImportedPrimaryKeys(deploy);
|
||||
DeployBeanPropertyAssocOne<?> deployId = deploy.getIdClassProperty();
|
||||
if (deployId != null) {
|
||||
this.id = new BeanPropertyIdClass(owner, desc, deployId);
|
||||
setImportedPrimaryKeysFor(deploy, deployId);
|
||||
} else {
|
||||
setImportedPrimaryKeys(deploy);
|
||||
}
|
||||
|
||||
DeployBeanProperty deployOrderColumn = deploy.getOrderColumn();
|
||||
this.orderColumn = deployOrderColumn != null ? new BeanPropertyOrderColumn(desc, deployOrderColumn) : null;
|
||||
@@ -142,23 +149,43 @@ public class DeployBeanPropertyLists {
|
||||
* </p>
|
||||
*/
|
||||
private void setImportedPrimaryKeys(DeployBeanDescriptor<?> deploy) {
|
||||
DeployBeanProperty id = deploy.idProperty();
|
||||
if (id instanceof DeployBeanPropertyAssocOne<?>) {
|
||||
setImportedPrimaryKeysFor(deploy, (DeployBeanPropertyAssocOne<?>) id);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
private void setImportedPrimaryKeysFor(DeployBeanDescriptor<?> deploy, DeployBeanPropertyAssocOne<?> id) {
|
||||
|
||||
for (DeployBeanProperty prop : id.getTargetDeploy().properties()) {
|
||||
DeployBeanProperty match = findImported(deploy, prop);
|
||||
if (match != null) {
|
||||
match.setImportedPrimaryKeyColumn(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DeployBeanProperty findImported(DeployBeanDescriptor<?> deploy, DeployBeanProperty embeddedScalar) {
|
||||
|
||||
// the logical name and db column we are looking for a match on
|
||||
String name = embeddedScalar.getName();
|
||||
String dbColumn = embeddedScalar.getDbColumn();
|
||||
|
||||
DeployBeanProperty match = deploy.getBeanProperty(name);
|
||||
if (match != null) {
|
||||
return match;
|
||||
}
|
||||
// could look to match more by dbColumn
|
||||
|
||||
for (DeployBeanPropertyAssocOne<?> assocOne : deploy.propertiesAssocOne()) {
|
||||
if (name.equals(assocOne.getName()) || (dbColumn != null && dbColumn.equals(assocOne.getDbColumn()))) {
|
||||
return assocOne;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the unidirectional.
|
||||
*/
|
||||
@@ -188,12 +215,13 @@ public class DeployBeanPropertyLists {
|
||||
return;
|
||||
}
|
||||
if (prop.isId()) {
|
||||
ids.add(prop);
|
||||
if (id != null) {
|
||||
throw new IllegalStateException("More that one @Id property on " + desc.getFullName() + " ?");
|
||||
}
|
||||
id = prop;
|
||||
return;
|
||||
} else {
|
||||
nonTransients.add(prop);
|
||||
}
|
||||
|
||||
nonTransients.add(prop);
|
||||
if (prop.isMutableScalarType()) {
|
||||
mutable.add(prop);
|
||||
}
|
||||
@@ -255,15 +283,7 @@ public class DeployBeanPropertyLists {
|
||||
}
|
||||
|
||||
public BeanProperty getId() {
|
||||
if (ids.size() > 1) {
|
||||
String msg = "Issue with bean " + desc + ". Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
|
||||
+ " Please email the ebean google group if you need further clarification.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
if (ids.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return ids.get(0);
|
||||
return id;
|
||||
}
|
||||
|
||||
public BeanProperty[] getNonTransients() {
|
||||
|
||||
@@ -4,9 +4,6 @@ import io.ebeaninternal.server.deploy.BeanDescriptorMap;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Used for associated beans in place of a BeanDescriptor. This is done to avoid
|
||||
* recursion issues due to the potentially bi-directional and circular
|
||||
@@ -25,12 +22,12 @@ public class DeployBeanTable {
|
||||
*/
|
||||
private String baseTable;
|
||||
|
||||
private List<DeployBeanProperty> idProperties;
|
||||
private DeployBeanProperty idProperty;
|
||||
|
||||
/**
|
||||
* Create the BeanTable.
|
||||
*/
|
||||
public DeployBeanTable(Class<?> beanType) {
|
||||
DeployBeanTable(Class<?> beanType) {
|
||||
this.beanType = beanType;
|
||||
}
|
||||
|
||||
@@ -53,12 +50,8 @@ public class DeployBeanTable {
|
||||
/**
|
||||
* Return the id properties.
|
||||
*/
|
||||
public BeanProperty[] createIdProperties(BeanDescriptorMap owner) {
|
||||
BeanProperty[] props = new BeanProperty[idProperties.size()];
|
||||
for (int i = 0; i < idProperties.size(); i++) {
|
||||
props[i] = createProperty(owner, idProperties.get(i));
|
||||
}
|
||||
return props;
|
||||
public BeanProperty createIdProperty(BeanDescriptorMap owner) {
|
||||
return idProperty == null ? null : createProperty(owner, idProperty);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@@ -70,14 +63,13 @@ public class DeployBeanTable {
|
||||
} else {
|
||||
return new BeanProperty(prop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Id properties.
|
||||
*/
|
||||
public void setIdProperties(List<DeployBeanProperty> idProperties) {
|
||||
this.idProperties = idProperties;
|
||||
public void setIdProperty(DeployBeanProperty idProperty) {
|
||||
this.idProperty = idProperty;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,9 +92,9 @@ public class DeployTableJoinColumn {
|
||||
|
||||
private void setReferencedColumn(BeanTable beanTable) {
|
||||
if (localDbColumn == null) {
|
||||
BeanProperty[] idProperties = beanTable.getIdProperties();
|
||||
if (idProperties.length == 1) {
|
||||
localDbColumn = idProperties[0].getDbColumn();
|
||||
BeanProperty idProperty = beanTable.getIdProperty();
|
||||
if (idProperty != null) {
|
||||
localDbColumn = idProperty.getDbColumn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,8 +247,8 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
}
|
||||
if (!intJoin.hasJoinColumns()) {
|
||||
// define foreign key columns
|
||||
BeanProperty[] localIds = localTable.getIdProperties();
|
||||
for (BeanProperty localId : localIds) {
|
||||
BeanProperty localId = localTable.getIdProperty();
|
||||
if (localId != null) {
|
||||
// add the source to intersection join columns
|
||||
String fkCol = localTableName + "_" + localId.getDbColumn();
|
||||
intJoin.addJoinColumn(new DeployTableJoinColumn(localId.getDbColumn(), namingConvention.getColumnFromProperty(null, fkCol)));
|
||||
@@ -257,8 +257,8 @@ class AnnotationAssocManys extends AnnotationParser {
|
||||
|
||||
if (!destJoin.hasJoinColumns()) {
|
||||
// define inverse foreign key columns
|
||||
BeanProperty[] otherIds = otherTable.getIdProperties();
|
||||
for (BeanProperty otherId : otherIds) {
|
||||
BeanProperty otherId = otherTable.getIdProperty();
|
||||
if (otherId != null) {
|
||||
// set the intersection to dest table join columns
|
||||
final String fkCol = otherTableName + "_" + otherId.getDbColumn();
|
||||
destJoin.addJoinColumn(new DeployTableJoinColumn(namingConvention.getColumnFromProperty(null, fkCol), otherId.getDbColumn()));
|
||||
|
||||
@@ -92,9 +92,7 @@ public class AnnotationAssocOnes extends AnnotationParser {
|
||||
// May as well check for Id. Makes sense to me.
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setEmbedded();
|
||||
prop.setId();
|
||||
prop.setNullable(false);
|
||||
readIdAssocOne(prop);
|
||||
}
|
||||
|
||||
DbForeignKey dbForeignKey = get(prop, DbForeignKey.class);
|
||||
|
||||
@@ -23,6 +23,7 @@ import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.IdClass;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
@@ -127,6 +128,11 @@ public class AnnotationClass extends AnnotationParser {
|
||||
}
|
||||
}
|
||||
|
||||
IdClass idClass = AnnotationUtil.findAnnotationRecursive(cls, IdClass.class);
|
||||
if (idClass != null) {
|
||||
descriptor.setIdClass(idClass.value());
|
||||
}
|
||||
|
||||
Embeddable embeddable = AnnotationUtil.findAnnotationRecursive(cls, Embeddable.class);
|
||||
if (embeddable != null) {
|
||||
descriptor.setEntityType(EntityType.EMBEDDED);
|
||||
|
||||
@@ -91,7 +91,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
*/
|
||||
private FetchType defaultLobFetchType = FetchType.LAZY;
|
||||
|
||||
public AnnotationFields(GeneratedPropertyFactory generatedPropFactory, DeployBeanInfo<?> info,
|
||||
AnnotationFields(GeneratedPropertyFactory generatedPropFactory, DeployBeanInfo<?> info,
|
||||
boolean javaxValidationAnnotations, boolean jacksonAnnotationsPresent, boolean eagerFetchLobs) {
|
||||
|
||||
super(info, javaxValidationAnnotations);
|
||||
@@ -127,8 +127,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
prop.setId();
|
||||
prop.setNullable(false);
|
||||
readIdAssocOne(prop);
|
||||
}
|
||||
|
||||
EmbeddedId embeddedId = get(prop, EmbeddedId.class);
|
||||
@@ -211,7 +210,7 @@ public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
Id id = get(prop, Id.class);
|
||||
if (id != null) {
|
||||
readId(prop);
|
||||
readIdScalar(prop);
|
||||
}
|
||||
|
||||
// determine the JDBC type using Lob/Temporal
|
||||
@@ -517,18 +516,6 @@ public class AnnotationFields extends AnnotationParser {
|
||||
return util.createDataEncryptSupport(table, column);
|
||||
}
|
||||
|
||||
private void readId(DeployBeanProperty prop) {
|
||||
|
||||
prop.setId();
|
||||
prop.setNullable(false);
|
||||
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
if (descriptor.getIdGeneratorName() == null) {
|
||||
descriptor.setUuidGenerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readGenValue(GeneratedValue gen, DeployBeanProperty prop) {
|
||||
|
||||
String genName = gen.generator();
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.deploy.parse;
|
||||
import io.ebeaninternal.server.deploy.BeanCascadeInfo;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import io.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
|
||||
import javax.persistence.AttributeOverride;
|
||||
@@ -11,6 +12,7 @@ import javax.persistence.Column;
|
||||
import javax.validation.groups.Default;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Base class for reading deployment annotations.
|
||||
@@ -39,6 +41,36 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
@Override
|
||||
public abstract void parse();
|
||||
|
||||
/**
|
||||
* Read the Id annotation on an embeddedId.
|
||||
*/
|
||||
protected void readIdAssocOne(DeployBeanPropertyAssoc<?> prop) {
|
||||
prop.setNullable(false);
|
||||
if (prop.isIdClass()) {
|
||||
prop.setImportedPrimaryKey();
|
||||
} else {
|
||||
prop.setId();
|
||||
prop.setEmbedded();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the Id annotation on scalar property.
|
||||
*/
|
||||
protected void readIdScalar(DeployBeanProperty prop) {
|
||||
prop.setNullable(false);
|
||||
if (prop.isIdClass()) {
|
||||
prop.setImportedPrimaryKey();
|
||||
} else {
|
||||
prop.setId();
|
||||
if (prop.getPropertyType().equals(UUID.class)) {
|
||||
if (descriptor.getIdGeneratorName() == null) {
|
||||
descriptor.setUuidGenerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to set cascade types to the CascadeInfo on BeanProperty.
|
||||
*/
|
||||
|
||||
@@ -83,6 +83,7 @@ public class ReadAnnotations {
|
||||
new AnnotationSql(info, javaxValidationAnnotations).parse();
|
||||
|
||||
new AnnotationClass(info).parseAttributeOverride();
|
||||
info.getDescriptor().postAnnotations();
|
||||
|
||||
} catch (RuntimeException e) {
|
||||
throw new RuntimeException("Error reading annotations for " + info, e);
|
||||
|
||||
@@ -69,7 +69,6 @@ public class InsertHandler extends DmlHandler {
|
||||
// expecting a concatenated key that can
|
||||
// be built from supplied AssocOne beans
|
||||
withId = meta.deriveConcatenatedId(persistRequest);
|
||||
|
||||
} else if (meta.supportsGetGeneratedKeys()) {
|
||||
// Identity with getGeneratedKeys
|
||||
useGeneratedKeys = true;
|
||||
|
||||
@@ -2,7 +2,6 @@ package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.core.PersistRequestBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
import io.ebeaninternal.server.persist.dml.GenerateDmlRequest;
|
||||
@@ -15,7 +14,7 @@ import java.util.List;
|
||||
/**
|
||||
* Bindable for a EmbeddedId.
|
||||
*/
|
||||
public final class BindableIdEmbedded implements BindableId {
|
||||
final class BindableIdEmbedded implements BindableId {
|
||||
|
||||
private final BeanPropertyAssocOne<?> embId;
|
||||
|
||||
@@ -23,10 +22,10 @@ public final class BindableIdEmbedded implements BindableId {
|
||||
|
||||
private final MatchedImportedProperty[] matches;
|
||||
|
||||
public BindableIdEmbedded(BeanPropertyAssocOne<?> embId, BeanDescriptor<?> desc) {
|
||||
BindableIdEmbedded(BeanPropertyAssocOne<?> embId, MatchedImportedProperty[] matches) {
|
||||
this.embId = embId;
|
||||
this.props = embId.getProperties();
|
||||
matches = MatchedImportedProperty.build(props, desc);
|
||||
this.matches = matches;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,13 +66,10 @@ public final class BindableIdEmbedded implements BindableId {
|
||||
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
|
||||
|
||||
EntityBean idValue = (EntityBean) embId.getValue(bean);
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
|
||||
Object value = prop.getValue(idValue);
|
||||
request.bind(value, prop);
|
||||
}
|
||||
|
||||
request.setIdValue(idValue);
|
||||
}
|
||||
|
||||
@@ -88,7 +84,7 @@ public final class BindableIdEmbedded implements BindableId {
|
||||
public boolean deriveConcatenatedId(PersistRequestBean<?> persist) {
|
||||
|
||||
if (matches == null) {
|
||||
String m = "Matches for the concatenated key columns where not found?"
|
||||
String m = "No matches for " + embId.getFullBeanName() + " 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);
|
||||
@@ -100,8 +96,8 @@ public final class BindableIdEmbedded implements BindableId {
|
||||
EntityBean newId = (EntityBean) embId.createEmbeddedId();
|
||||
|
||||
// populate it from the assoc one id values...
|
||||
for (MatchedImportedProperty matche : matches) {
|
||||
matche.populate(bean, newId);
|
||||
for (MatchedImportedProperty match : matches) {
|
||||
match.populate(bean, newId);
|
||||
}
|
||||
|
||||
// support PropertyChangeSupport
|
||||
|
||||
@@ -27,9 +27,11 @@ public class FactoryBaseProperties {
|
||||
public void create(List<Bindable> list, BeanDescriptor<?> desc, DmlMode mode, boolean withLobs) {
|
||||
|
||||
for (BeanProperty prop : desc.propertiesBaseScalar()) {
|
||||
Bindable item = factoryProperty.create(prop, mode, withLobs);
|
||||
if (item != null) {
|
||||
list.add(item);
|
||||
if (!prop.isImportedPrimaryKey()) {
|
||||
Bindable item = factoryProperty.create(prop, mode, withLobs);
|
||||
if (item != null) {
|
||||
list.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,18 +27,14 @@ public class FactoryEmbedded {
|
||||
BeanPropertyAssocOne<?>[] embedded = desc.propertiesEmbedded();
|
||||
|
||||
for (BeanPropertyAssocOne<?> anEmbedded : embedded) {
|
||||
|
||||
BeanProperty[] props = anEmbedded.getProperties();
|
||||
|
||||
List<Bindable> bindList = new ArrayList<>(props.length);
|
||||
|
||||
for (BeanProperty prop : props) {
|
||||
Bindable item = factoryProperty.create(prop, mode, withLobs);
|
||||
if (item != null) {
|
||||
bindList.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
list.add(new BindableEmbedded(anEmbedded, bindList));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +20,14 @@ public class FactoryId {
|
||||
BeanProperty id = desc.getIdProperty();
|
||||
if (id == null) {
|
||||
return new BindableIdEmpty();
|
||||
|
||||
}
|
||||
if (!id.isEmbedded()) {
|
||||
return new BindableIdScalar(id);
|
||||
|
||||
} else {
|
||||
BeanPropertyAssocOne<?> embId = (BeanPropertyAssocOne<?>) id;
|
||||
return new BindableIdEmbedded(embId, desc);
|
||||
MatchedImportedProperty[] matches = MatchedImportedFactory.build(embId.getProperties(), desc);
|
||||
return new BindableIdEmbedded(embId, matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Matches local embedded id properties to 'matching' properties from a
|
||||
* ManyToOne associated bean that is a 'imported primary key'.
|
||||
*/
|
||||
class MatchedImportedEmbedded implements MatchedImportedProperty {
|
||||
|
||||
private final BeanProperty localProp;
|
||||
|
||||
private final BeanPropertyAssocOne<?> assocOne;
|
||||
|
||||
private final BeanProperty foreignProp;
|
||||
|
||||
MatchedImportedEmbedded(BeanProperty localProp, BeanPropertyAssocOne<?> assocOne, BeanProperty foreignProp) {
|
||||
this.localProp = localProp;
|
||||
this.assocOne = assocOne;
|
||||
this.foreignProp = foreignProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populate(EntityBean sourceBean, EntityBean embeddedId) {
|
||||
Object assocBean = assocOne.getValue(sourceBean);
|
||||
if (assocBean == null) {
|
||||
throw new NullPointerException("The assoc bean for " + assocOne + " is null?");
|
||||
}
|
||||
Object value = foreignProp.getValue((EntityBean) assocBean);
|
||||
localProp.setValue(embeddedId, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
class MatchedImportedFactory {
|
||||
|
||||
/**
|
||||
* Create the array of matchedImportedProperty based on the properties and descriptor.
|
||||
*/
|
||||
protected static MatchedImportedProperty[] build(BeanProperty[] props, BeanDescriptor<?> desc) {
|
||||
|
||||
MatchedImportedProperty[] matches = new MatchedImportedProperty[props.length];
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
// find matching assoc one property for dbColumn
|
||||
matches[i] = findMatch(props[i], desc);
|
||||
if (matches[i] == null) {
|
||||
// ok, the assoc ones are not on the bean?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private static MatchedImportedProperty findMatch(BeanProperty prop, BeanDescriptor<?> desc) {
|
||||
|
||||
// find matching against the local database column
|
||||
String dbColumn = prop.getDbColumn();
|
||||
|
||||
BeanPropertyAssocOne<?>[] assocOnes = desc.propertiesOne();
|
||||
for (BeanPropertyAssocOne<?> assocOne1 : assocOnes) {
|
||||
if (assocOne1.isImportedPrimaryKey()) {
|
||||
// search using the ImportedId from the assoc one
|
||||
BeanProperty foreignMatch = assocOne1.getImportedId().findMatchImport(dbColumn);
|
||||
if (foreignMatch != null) {
|
||||
return new MatchedImportedEmbedded(prop, assocOne1, foreignMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BeanProperty[] scalar = desc.propertiesBaseScalar();
|
||||
for (BeanProperty beanProperty : scalar) {
|
||||
if (dbColumn.equals(beanProperty.getDbColumn())) {
|
||||
return new MatchedImportedScalar(prop, beanProperty);
|
||||
}
|
||||
}
|
||||
|
||||
// there was no matching assoc one property.
|
||||
// example UserRole bean missing assoc one to User?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,86 +1,11 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
import io.ebeaninternal.server.deploy.BeanPropertyAssocOne;
|
||||
|
||||
/**
|
||||
* Matches local embedded id properties to 'matching' properties from a
|
||||
* ManyToOne associated bean that is a 'imported primary key'.
|
||||
* <p>
|
||||
* This object is designed to help BindableIdEmbedded and BindableIdMap to
|
||||
* create a concatenated id from the id values from ManyToOne associated beans.
|
||||
* This can be done when those ManyToOne associated beans make up the primary
|
||||
* key. This typically means the BindableIdEmbedded is for a intersection table
|
||||
* of a Many to Many relationship.
|
||||
* </p>
|
||||
*/
|
||||
class MatchedImportedProperty {
|
||||
|
||||
private final BeanPropertyAssocOne<?> assocOne;
|
||||
|
||||
private final BeanProperty foreignProp;
|
||||
|
||||
private final BeanProperty localProp;
|
||||
|
||||
protected MatchedImportedProperty(BeanPropertyAssocOne<?> assocOne, BeanProperty foreignProp,
|
||||
BeanProperty localProp) {
|
||||
this.assocOne = assocOne;
|
||||
this.foreignProp = foreignProp;
|
||||
this.localProp = localProp;
|
||||
}
|
||||
|
||||
protected void populate(EntityBean sourceBean, EntityBean destBean) {
|
||||
Object assocBean = assocOne.getValue(sourceBean);
|
||||
if (assocBean == null) {
|
||||
String msg = "The assoc bean for " + assocOne + " is null?";
|
||||
throw new NullPointerException(msg);
|
||||
}
|
||||
|
||||
Object value = foreignProp.getValue((EntityBean) assocBean);
|
||||
localProp.setValue(destBean, value);
|
||||
}
|
||||
public interface MatchedImportedProperty {
|
||||
|
||||
/**
|
||||
* Create the array of matchedImportedProperty based on the properties and descriptor.
|
||||
* Populate the embeddedId bean from the source entity.
|
||||
*/
|
||||
protected static MatchedImportedProperty[] build(BeanProperty[] props, BeanDescriptor<?> desc) {
|
||||
|
||||
MatchedImportedProperty[] matches = new MatchedImportedProperty[props.length];
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
// find matching assoc one property for dbColumn
|
||||
matches[i] = MatchedImportedProperty.findMatch(props[i], desc);
|
||||
if (matches[i] == null) {
|
||||
// ok, the assoc ones are not on the bean?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
|
||||
private static MatchedImportedProperty findMatch(BeanProperty prop, BeanDescriptor<?> desc) {
|
||||
|
||||
// find matching against the local database column
|
||||
String dbColumn = prop.getDbColumn();
|
||||
|
||||
BeanPropertyAssocOne<?>[] assocOnes = desc.propertiesOne();
|
||||
for (BeanPropertyAssocOne<?> assocOne1 : assocOnes) {
|
||||
if (assocOne1.isImportedPrimaryKey()) {
|
||||
|
||||
// search using the ImportedId from the assoc one
|
||||
BeanProperty foreignMatch = assocOne1.getImportedId().findMatchImport(dbColumn);
|
||||
|
||||
if (foreignMatch != null) {
|
||||
return new MatchedImportedProperty(assocOne1, foreignMatch, prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// there was no matching assoc one property.
|
||||
// example UserRole bean missing assoc one to User?
|
||||
return null;
|
||||
}
|
||||
|
||||
void populate(EntityBean sourceBean, EntityBean embeddedId);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package io.ebeaninternal.server.persist.dmlbind;
|
||||
|
||||
import io.ebean.bean.EntityBean;
|
||||
import io.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Matches local embedded id properties to 'matching' imported primary key scalar properties.
|
||||
*/
|
||||
class MatchedImportedScalar implements MatchedImportedProperty {
|
||||
|
||||
private final BeanProperty localProp;
|
||||
|
||||
private final BeanProperty foreignProp;
|
||||
|
||||
MatchedImportedScalar(BeanProperty localProp, BeanProperty foreignProp) {
|
||||
this.localProp = localProp;
|
||||
this.foreignProp = foreignProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populate(EntityBean sourceBean, EntityBean embeddedId) {
|
||||
|
||||
Object value = foreignProp.getValue(sourceBean);
|
||||
localProp.setValue(embeddedId, value);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user