in grails-datastore-gorm-hibernate/src/main/groovy/org/grails/orm/hibernate/cfg/GrailsDomainBinder.java [342:491]
protected void bindCollectionSecondPass(ToMany property, InFlightMetadataCollector mappings,
Map<?, ?> persistentClasses, Collection collection, String sessionFactoryBeanName) {
PersistentClass associatedClass = null;
if (LOG.isDebugEnabled())
LOG.debug("Mapping collection: "
+ collection.getRole()
+ " -> "
+ collection.getCollectionTable().getName());
PropertyConfig propConfig = getPropertyConfig(property);
PersistentEntity referenced = property.getAssociatedEntity();
if (propConfig != null && StringUtils.hasText(propConfig.getSort())) {
if (!property.isBidirectional() && (property instanceof org.grails.datastore.mapping.model.types.OneToMany)) {
throw new DatastoreConfigurationException("Default sort for associations ["+property.getOwner().getName()+"->" + property.getName() +
"] are not supported with unidirectional one to many relationships.");
}
if (referenced != null) {
PersistentProperty propertyToSortBy = referenced.getPropertyByName(propConfig.getSort());
String associatedClassName = property.getAssociatedEntity().getName();
associatedClass = (PersistentClass) persistentClasses.get(associatedClassName);
if (associatedClass != null) {
collection.setOrderBy(buildOrderByClause(propertyToSortBy.getName(), associatedClass, collection.getRole(),
propConfig.getOrder() != null ? propConfig.getOrder() : "asc"));
}
}
}
// Configure one-to-many
if (collection.isOneToMany()) {
Mapping m = getRootMapping(referenced);
boolean tablePerSubclass = m != null && !m.getTablePerHierarchy();
if (referenced != null && !referenced.isRoot() && !tablePerSubclass) {
Mapping rootMapping = getRootMapping(referenced);
String discriminatorColumnName = RootClass.DEFAULT_DISCRIMINATOR_COLUMN_NAME;
if (rootMapping != null) {
DiscriminatorConfig discriminatorConfig = rootMapping.getDiscriminator();
if(discriminatorConfig != null) {
final ColumnConfig discriminatorColumn = discriminatorConfig.getColumn();
if (discriminatorColumn != null) {
discriminatorColumnName = discriminatorColumn.getName();
}
if (discriminatorConfig.getFormula() != null) {
discriminatorColumnName = discriminatorConfig.getFormula();
}
}
}
//NOTE: this will build the set for the in clause if it has sublcasses
Set<String> discSet = buildDiscriminatorSet((HibernatePersistentEntity) referenced);
String inclause = String.join(",", discSet);
collection.setWhere(discriminatorColumnName + " in (" + inclause + ")");
}
OneToMany oneToMany = (OneToMany) collection.getElement();
String associatedClassName = oneToMany.getReferencedEntityName();
associatedClass = (PersistentClass) persistentClasses.get(associatedClassName);
// if there is no persistent class for the association throw exception
if (associatedClass == null) {
throw new MappingException("Association references unmapped class: " + oneToMany.getReferencedEntityName());
}
oneToMany.setAssociatedClass(associatedClass);
if (shouldBindCollectionWithForeignKey(property)) {
collection.setCollectionTable(associatedClass.getTable());
}
bindCollectionForPropertyConfig(collection, propConfig);
}
final boolean isManyToMany = property instanceof ManyToMany;
if(referenced != null && !isManyToMany && referenced.isMultiTenant()) {
String filterCondition = getMultiTenantFilterCondition(sessionFactoryBeanName, referenced);
if(filterCondition != null) {
if (isUnidirectionalOneToMany(property)) {
collection.addManyToManyFilter(GormProperties.TENANT_IDENTITY, filterCondition, true, Collections.emptyMap(), Collections.emptyMap());
} else {
collection.addFilter(GormProperties.TENANT_IDENTITY, filterCondition, true, Collections.emptyMap(), Collections.emptyMap());
}
}
}
if (isSorted(property)) {
collection.setSorted(true);
}
// setup the primary key references
DependantValue key = createPrimaryKeyValue(mappings, property, collection, persistentClasses);
// link a bidirectional relationship
if (property.isBidirectional()) {
Association otherSide = property.getInverseSide();
if ((otherSide instanceof org.grails.datastore.mapping.model.types.ToOne) && shouldBindCollectionWithForeignKey(property)) {
linkBidirectionalOneToMany(collection, associatedClass, key, otherSide);
} else if ((otherSide instanceof ManyToMany) || Map.class.isAssignableFrom(property.getType())) {
bindDependentKeyValue(property, key, mappings, sessionFactoryBeanName);
}
} else {
if (hasJoinKeyMapping(propConfig)) {
bindSimpleValue("long", key,false, propConfig.getJoinTable().getKey().getName(), mappings);
} else {
bindDependentKeyValue(property, key, mappings, sessionFactoryBeanName);
}
}
collection.setKey(key);
// get cache config
if (propConfig != null) {
CacheConfig cacheConfig = propConfig.getCache();
if (cacheConfig != null) {
collection.setCacheConcurrencyStrategy(cacheConfig.getUsage());
}
}
// if we have a many-to-many
if (isManyToMany || isBidirectionalOneToManyMap(property)) {
PersistentProperty otherSide = property.getInverseSide();
if (property.isBidirectional()) {
if (LOG.isDebugEnabled())
LOG.debug("[GrailsDomainBinder] Mapping other side " + otherSide.getOwner().getName() + "." + otherSide.getName() + " -> " + collection.getCollectionTable().getName() + " as ManyToOne");
ManyToOne element = new ManyToOne(metadataBuildingContext, collection.getCollectionTable());
bindManyToMany((Association)otherSide, element, mappings, sessionFactoryBeanName);
collection.setElement(element);
bindCollectionForPropertyConfig(collection, propConfig);
if (property.isCircular()) {
collection.setInverse(false);
}
} else {
// TODO support unidirectional many-to-many
}
} else if (shouldCollectionBindWithJoinColumn(property)) {
bindCollectionWithJoinTable(property, mappings, collection, propConfig, sessionFactoryBeanName);
} else if (isUnidirectionalOneToMany(property)) {
// for non-inverse one-to-many, with a not-null fk, add a backref!
// there are problems with list and map mappings and join columns relating to duplicate key constraints
// TODO change this when HHH-1268 is resolved
bindUnidirectionalOneToMany((org.grails.datastore.mapping.model.types.OneToMany) property, mappings, collection);
}
}