use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.
the class JoinSequence method toJoinFragment.
public JoinFragment toJoinFragment(Map enabledFilters, boolean includeAllSubclassJoins, boolean renderSubclassJoins, String withClauseFragment) throws MappingException {
final QueryJoinFragment joinFragment = new QueryJoinFragment(factory.getDialect(), useThetaStyle);
Iterator<Join> iter;
Join first;
Joinable last;
if (rootJoinable != null) {
joinFragment.addCrossJoin(rootJoinable.getTableName(), rootAlias);
final String filterCondition = rootJoinable.filterFragment(rootAlias, enabledFilters, treatAsDeclarations);
// JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
// can put the where clause fragment in the right place in the SQL AST. 'hasFilterCondition' keeps track
// of that fact.
joinFragment.setHasFilterCondition(joinFragment.addCondition(filterCondition));
addSubclassJoins(joinFragment, rootAlias, rootJoinable, true, includeAllSubclassJoins, treatAsDeclarations);
last = rootJoinable;
} else if (needsTableGroupJoin(joins, withClauseFragment)) {
iter = joins.iterator();
first = iter.next();
final String joinString;
switch(first.joinType) {
case INNER_JOIN:
joinString = " inner join ";
break;
case LEFT_OUTER_JOIN:
joinString = " left outer join ";
break;
case RIGHT_OUTER_JOIN:
joinString = " right outer join ";
break;
case FULL_JOIN:
joinString = " full outer join ";
break;
default:
throw new AssertionFailure("undefined join type");
}
joinFragment.addFromFragmentString(joinString);
joinFragment.addFromFragmentString(" (");
joinFragment.addFromFragmentString(first.joinable.getTableName());
joinFragment.addFromFragmentString(" ");
joinFragment.addFromFragmentString(first.getAlias());
for (Join join : joins) {
// Skip joining the first join node as it is contained in the subquery
if (join != first) {
joinFragment.addJoin(join.getJoinable().getTableName(), join.getAlias(), join.getLHSColumns(), JoinHelper.getRHSColumnNames(join.getAssociationType(), factory), join.joinType);
}
addSubclassJoins(joinFragment, join.getAlias(), join.getJoinable(), // TODO: Think about if this could be made always true
join.joinType == JoinType.INNER_JOIN, includeAllSubclassJoins, // builds the JoinSequence for HQL joins
treatAsDeclarations);
}
joinFragment.addFromFragmentString(")");
joinFragment.addFromFragmentString(" on ");
final String rhsAlias = first.getAlias();
final String[][] lhsColumns = first.getLHSColumns();
final String[] rhsColumns = JoinHelper.getRHSColumnNames(first.getAssociationType(), factory);
if (lhsColumns.length > 1) {
joinFragment.addFromFragmentString("(");
}
for (int i = 0; i < lhsColumns.length; i++) {
for (int j = 0; j < lhsColumns[i].length; j++) {
joinFragment.addFromFragmentString(lhsColumns[i][j]);
joinFragment.addFromFragmentString("=");
joinFragment.addFromFragmentString(rhsAlias);
joinFragment.addFromFragmentString(".");
joinFragment.addFromFragmentString(rhsColumns[j]);
if (j < lhsColumns[i].length - 1) {
joinFragment.addFromFragmentString(" and ");
}
}
if (i < lhsColumns.length - 1) {
joinFragment.addFromFragmentString(" or ");
}
}
if (lhsColumns.length > 1) {
joinFragment.addFromFragmentString(")");
}
joinFragment.addFromFragmentString(" and ");
joinFragment.addFromFragmentString(withClauseFragment);
return joinFragment;
} else {
last = null;
}
for (Join join : joins) {
// technically the treatAsDeclarations should only apply to rootJoinable or to a single Join,
// but that is not possible atm given how these JoinSequence and Join objects are built.
// However, it is generally ok given how the HQL parser builds these JoinSequences (a HQL join
// results in a JoinSequence with an empty rootJoinable and a single Join). So we use that here
// as an assumption
final String on = join.getAssociationType().getOnCondition(join.getAlias(), factory, enabledFilters, treatAsDeclarations);
String condition;
if (last != null && isManyToManyRoot(last) && ((QueryableCollection) last).getElementType() == join.getAssociationType()) {
// the current join represents the join between a many-to-many association table
// and its "target" table. Here we need to apply any additional filters
// defined specifically on the many-to-many
final String manyToManyFilter = ((QueryableCollection) last).getManyToManyFilterFragment(join.getAlias(), enabledFilters);
condition = "".equals(manyToManyFilter) ? on : "".equals(on) ? manyToManyFilter : on + " and " + manyToManyFilter;
} else {
condition = on;
}
if (withClauseFragment != null && !isManyToManyRoot(join.joinable)) {
condition += " and " + withClauseFragment;
}
joinFragment.addJoin(join.getJoinable().getTableName(), join.getAlias(), join.getLHSColumns(), JoinHelper.getRHSColumnNames(join.getAssociationType(), factory), join.joinType, condition);
if (renderSubclassJoins) {
addSubclassJoins(joinFragment, join.getAlias(), join.getJoinable(), join.joinType == JoinType.INNER_JOIN, includeAllSubclassJoins, // builds the JoinSequence for HQL joins
treatAsDeclarations);
}
last = join.getJoinable();
}
if (next != null) {
joinFragment.addFragment(next.toJoinFragment(enabledFilters, includeAllSubclassJoins));
}
joinFragment.addCondition(conditions.toString());
if (isFromPart) {
joinFragment.clearWherePart();
}
return joinFragment;
}
use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.
the class LoadQueryJoinAndFetchProcessor method processEntityFetch.
private void processEntityFetch(SelectStatementBuilder selectStatementBuilder, FetchSource fetchSource, EntityFetch fetch, ReaderCollector readerCollector, FetchStatsImpl fetchStats) {
// todo : still need to think through expressing bi-directionality in the new model...
// if ( BidirectionalEntityFetch.class.isInstance( fetch ) ) {
// log.tracef( "Skipping bi-directional entity fetch [%s]", fetch );
// return;
// }
fetchStats.processingFetch(fetch);
if (!FetchStrategyHelper.isJoinFetched(fetch.getFetchStrategy())) {
// not join fetched, so nothing else to do
return;
}
// First write out the SQL SELECT fragments
final Joinable joinable = (Joinable) fetch.getEntityPersister();
EntityReferenceAliases aliases = aliasResolutionContext.resolveEntityReferenceAliases(fetch.getQuerySpaceUid());
// the null arguments here relate to many-to-many fetches
selectStatementBuilder.appendSelectClauseFragment(joinable.selectFragment(null, null, aliases.getTableAlias(), aliases.getColumnAliases().getSuffix(), null, true));
// process its identifier fetches first (building EntityReferenceInitializers for them if needed)
if (fetch.getIdentifierDescription().hasFetches()) {
final FetchSource entityIdentifierAsFetchSource = (FetchSource) fetch.getIdentifierDescription();
for (Fetch identifierFetch : entityIdentifierAsFetchSource.getFetches()) {
processFetch(selectStatementBuilder, fetch, identifierFetch, readerCollector, fetchStats);
}
}
// build an EntityReferenceInitializers for the incoming fetch itself
readerCollector.add(new EntityReferenceInitializerImpl(fetch, aliases));
// then visit each of our (non-identifier) fetches
processFetches(fetch, selectStatementBuilder, readerCollector, fetchStats);
}
use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.
the class LoadQueryJoinAndFetchProcessor method processCollectionFetch.
private void processCollectionFetch(SelectStatementBuilder selectStatementBuilder, FetchSource fetchSource, CollectionAttributeFetch fetch, ReaderCollector readerCollector, FetchStatsImpl fetchStats) {
fetchStats.processingFetch(fetch);
if (!FetchStrategyHelper.isJoinFetched(fetch.getFetchStrategy())) {
// not join fetched, so nothing else to do
return;
}
final CollectionReferenceAliases aliases = aliasResolutionContext.resolveCollectionReferenceAliases(fetch.getQuerySpaceUid());
final QueryableCollection queryableCollection = (QueryableCollection) fetch.getCollectionPersister();
final Joinable joinableCollection = (Joinable) fetch.getCollectionPersister();
if (fetch.getCollectionPersister().isManyToMany()) {
// todo : better way to access `ownerTableAlias` here.
// when processing the Join part of this we are able to look up the "lhs table alias" because we know
// the 'lhs' QuerySpace.
//
// Good idea to be able resolve a Join by lookup on the rhs and lhs uid? If so, Fetch
// for many-to-many we have 3 table aliases. By way of example, consider a normal m-n: User<->Role
// where User is the FetchOwner and Role (User.roles) is the Fetch. We'd have:
// 1) the owner's table : user
final String ownerTableAlias = aliasResolutionContext.resolveSqlTableAliasFromQuerySpaceUid(fetchSource.getQuerySpaceUid());
// 2) the m-n table : user_role
final String collectionTableAlias = aliases.getCollectionTableAlias();
// 3) the element table : role
final String elementTableAlias = aliases.getElementTableAlias();
// add select fragments from the collection table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
selectStatementBuilder.appendSelectClauseFragment(joinableCollection.selectFragment((Joinable) queryableCollection.getElementPersister(), elementTableAlias, collectionTableAlias, aliases.getEntityElementAliases().getColumnAliases().getSuffix(), aliases.getCollectionColumnAliases().getSuffix(), true));
// add select fragments from the element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister();
selectStatementBuilder.appendSelectClauseFragment(elementPersister.selectFragment(elementTableAlias, aliases.getEntityElementAliases().getColumnAliases().getSuffix()));
// add SQL ORDER-BY fragments
final String manyToManyOrdering = queryableCollection.getManyToManyOrderByString(elementTableAlias);
if (StringHelper.isNotEmpty(manyToManyOrdering)) {
selectStatementBuilder.appendOrderByFragment(manyToManyOrdering);
}
final String ordering = queryableCollection.getSQLOrderByString(collectionTableAlias);
if (StringHelper.isNotEmpty(ordering)) {
selectStatementBuilder.appendOrderByFragment(ordering);
}
readerCollector.add(new EntityReferenceInitializerImpl((EntityReference) fetch.getElementGraph(), aliasResolutionContext.resolveEntityReferenceAliases(fetch.getElementGraph().getQuerySpaceUid())));
} else {
// select the "collection columns"
selectStatementBuilder.appendSelectClauseFragment(queryableCollection.selectFragment(aliases.getElementTableAlias(), aliases.getCollectionColumnAliases().getSuffix()));
if (fetch.getCollectionPersister().isOneToMany()) {
// if the collection elements are entities, select the entity columns as well
final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister();
selectStatementBuilder.appendSelectClauseFragment(elementPersister.selectFragment(aliases.getElementTableAlias(), aliases.getEntityElementAliases().getColumnAliases().getSuffix()));
readerCollector.add(new EntityReferenceInitializerImpl((EntityReference) fetch.getElementGraph(), aliasResolutionContext.resolveEntityReferenceAliases(fetch.getElementGraph().getQuerySpaceUid())));
}
final String ordering = queryableCollection.getSQLOrderByString(aliases.getElementTableAlias());
if (StringHelper.isNotEmpty(ordering)) {
selectStatementBuilder.appendOrderByFragment(ordering);
}
}
if (fetch.getElementGraph() != null) {
processFetches(fetch.getElementGraph(), selectStatementBuilder, readerCollector);
}
readerCollector.add(new CollectionReferenceInitializerImpl(fetch, aliases));
}
use of org.hibernate.persister.entity.Joinable in project dhis2-core by dhis2.
the class HibernatePropertyIntrospector method updateJoinTables.
private void updateJoinTables() {
if (!roleToRoleComputing.compareAndSet(false, true)) {
// do it again
return;
}
Map<String, List<String>> joinTableToRoles = new HashMap<>();
SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) sessionFactory;
MetamodelImplementor metamodelImplementor = sessionFactoryImplementor.getMetamodel();
for (CollectionPersister collectionPersister : metamodelImplementor.collectionPersisters().values()) {
CollectionType collectionType = collectionPersister.getCollectionType();
if (collectionPersister.isManyToMany() && collectionType.isAssociationType()) {
Joinable associatedJoinable = collectionType.getAssociatedJoinable(sessionFactoryImplementor);
if (!joinTableToRoles.containsKey(associatedJoinable.getTableName())) {
joinTableToRoles.put(associatedJoinable.getTableName(), new ArrayList<>());
}
joinTableToRoles.get(associatedJoinable.getTableName()).add(collectionPersister.getRole());
} else if (collectionPersister.isInverse() && collectionType instanceof SetType) {
SetType setType = (SetType) collectionType;
setType.getAssociatedJoinable(sessionFactoryImplementor);
}
}
joinTableToRoles.entrySet().removeIf(entry -> entry.getValue().size() < 2);
for (Map.Entry<String, List<String>> entry : joinTableToRoles.entrySet()) {
roleToRole.put(entry.getValue().get(0), entry.getValue().get(1));
roleToRole.put(entry.getValue().get(1), entry.getValue().get(0));
}
}
use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.
the class FromElementFactory method createFromElement.
private FromElement createFromElement(EntityPersister entityPersister) {
Joinable joinable = (Joinable) entityPersister;
String text = joinable.getTableName();
AST ast = createFromElement(text);
FromElement element = (FromElement) ast;
return element;
}
Aggregations