use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class SessionImpl method logRemoveOrphanBeforeUpdates.
private void logRemoveOrphanBeforeUpdates(String timing, String entityName, Object entity) {
final EntityEntry entityEntry = persistenceContext.getEntry(entity);
log.tracef("%s remove orphan beforeQuery updates: [%s]", timing, entityEntry == null ? entityName : MessageHelper.infoString(entityName, entityEntry.getId()));
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class DynamicBatchingEntityLoaderBuilder method performOrderedMultiLoad.
@SuppressWarnings("unchecked")
private List performOrderedMultiLoad(OuterJoinLoadable persister, Serializable[] ids, SharedSessionContractImplementor session, MultiLoadOptions loadOptions) {
assert loadOptions.isOrderReturnEnabled();
final List result = CollectionHelper.arrayList(ids.length);
final LockOptions lockOptions = (loadOptions.getLockOptions() == null) ? new LockOptions(LockMode.NONE) : loadOptions.getLockOptions();
final int maxBatchSize;
if (loadOptions.getBatchSize() != null && loadOptions.getBatchSize() > 0) {
maxBatchSize = loadOptions.getBatchSize();
} else {
maxBatchSize = session.getJdbcServices().getJdbcEnvironment().getDialect().getDefaultBatchLoadSizingStrategy().determineOptimalBatchLoadSize(persister.getIdentifierType().getColumnSpan(session.getFactory()), ids.length);
}
final List<Serializable> idsInBatch = new ArrayList<>();
final List<Integer> elementPositionsLoadedByBatch = new ArrayList<>();
for (int i = 0; i < ids.length; i++) {
final Serializable id = ids[i];
final EntityKey entityKey = new EntityKey(id, persister);
if (loadOptions.isSessionCheckingEnabled()) {
// look for it in the Session first
final Object managedEntity = session.getPersistenceContext().getEntity(entityKey);
if (managedEntity != null) {
if (!loadOptions.isReturnOfDeletedEntitiesEnabled()) {
final EntityEntry entry = session.getPersistenceContext().getEntry(managedEntity);
if (entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE) {
// put a null in the result
result.add(i, null);
continue;
}
}
// if we did not hit the continue above, there is already an
// entry in the PC for that entity, so use it...
result.add(i, managedEntity);
continue;
}
}
// if we did not hit any of the continues above, then we need to batch
// load the entity state.
idsInBatch.add(ids[i]);
if (idsInBatch.size() >= maxBatchSize) {
performOrderedBatchLoad(idsInBatch, lockOptions, persister, session);
}
// Save the EntityKey instance for use later!
result.add(i, entityKey);
elementPositionsLoadedByBatch.add(i);
}
if (!idsInBatch.isEmpty()) {
performOrderedBatchLoad(idsInBatch, lockOptions, persister, session);
}
for (Integer position : elementPositionsLoadedByBatch) {
// the element value at this position in the result List should be
// the EntityKey for that entity; reuse it!
final EntityKey entityKey = (EntityKey) result.get(position);
Object entity = session.getPersistenceContext().getEntity(entityKey);
if (entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled()) {
// make sure it is not DELETED
final EntityEntry entry = session.getPersistenceContext().getEntry(entity);
if (entry.getStatus() == Status.DELETED || entry.getStatus() == Status.GONE) {
// the entity is locally deleted, and the options ask that we not return such entities...
entity = null;
}
}
result.set(position, entity);
}
return result;
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class AbstractEntityPersister method update.
/**
* Update an object
*/
public void update(final Serializable id, final Object[] fields, final int[] dirtyFields, final boolean hasDirtyCollection, final Object[] oldFields, final Object oldVersion, final Object object, final Object rowId, final SharedSessionContractImplementor session) throws HibernateException {
// apply any pre-update in-memory value generation
if (getEntityMetamodel().hasPreUpdateGeneratedValues()) {
final InMemoryValueGenerationStrategy[] strategies = getEntityMetamodel().getInMemoryValueGenerationStrategies();
for (int i = 0; i < strategies.length; i++) {
if (strategies[i] != null && strategies[i].getGenerationTiming().includesUpdate()) {
fields[i] = strategies[i].getValueGenerator().generateValue((Session) session, object);
setPropertyValue(object, i, fields[i]);
// todo : probably best to add to dirtyFields if not-null
}
}
}
//note: dirtyFields==null means we had no snapshot, and we couldn't get one using select-beforeQuery-update
// oldFields==null just means we had no snapshot to begin with (we might have used select-beforeQuery-update to get the dirtyFields)
final boolean[] tableUpdateNeeded = getTableUpdateNeeded(dirtyFields, hasDirtyCollection);
final int span = getTableSpan();
final boolean[] propsToUpdate;
final String[] updateStrings;
EntityEntry entry = session.getPersistenceContext().getEntry(object);
// in the process of being deleted.
if (entry == null && !isMutable()) {
throw new IllegalStateException("Updating immutable entity that is not in session yet!");
}
if ((entityMetamodel.isDynamicUpdate() && dirtyFields != null)) {
// We need to generate the UPDATE SQL when dynamic-update="true"
propsToUpdate = getPropertiesToUpdate(dirtyFields, hasDirtyCollection);
// don't need to check laziness (dirty checking algorithm handles that)
updateStrings = new String[span];
for (int j = 0; j < span; j++) {
updateStrings[j] = tableUpdateNeeded[j] ? generateUpdateString(propsToUpdate, j, oldFields, j == 0 && rowId != null) : null;
}
} else if (!isModifiableEntity(entry)) {
// We need to generate UPDATE SQL when a non-modifiable entity (e.g., read-only or immutable)
// needs:
// - to have references to transient entities set to null beforeQuery being deleted
// - to have version incremented do to a "dirty" association
// If dirtyFields == null, then that means that there are no dirty properties to
// to be updated; an empty array for the dirty fields needs to be passed to
// getPropertiesToUpdate() instead of null.
propsToUpdate = getPropertiesToUpdate((dirtyFields == null ? ArrayHelper.EMPTY_INT_ARRAY : dirtyFields), hasDirtyCollection);
// don't need to check laziness (dirty checking algorithm handles that)
updateStrings = new String[span];
for (int j = 0; j < span; j++) {
updateStrings[j] = tableUpdateNeeded[j] ? generateUpdateString(propsToUpdate, j, oldFields, j == 0 && rowId != null) : null;
}
} else {
// For the case of dynamic-update="false", or no snapshot, we use the static SQL
updateStrings = getUpdateStrings(rowId != null, hasUninitializedLazyProperties(object));
propsToUpdate = getPropertyUpdateability(object);
}
for (int j = 0; j < span; j++) {
// Now update only the tables with dirty properties (and the table with the version number)
if (tableUpdateNeeded[j]) {
updateOrInsert(id, fields, oldFields, j == 0 ? rowId : null, propsToUpdate, j, oldVersion, object, updateStrings[j], session);
}
}
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class AbstractEntityTuplizer method determineEntityIdPersistIfNecessary.
private static Serializable determineEntityIdPersistIfNecessary(Object entity, AssociationType associationType, SharedSessionContractImplementor session, SessionFactoryImplementor sessionFactory) {
if (entity == null) {
return null;
}
if (HibernateProxy.class.isInstance(entity)) {
// entity is a proxy, so we know it is not transient; just return ID from proxy
return ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier();
}
if (session != null) {
final EntityEntry pcEntry = session.getPersistenceContext().getEntry(entity);
if (pcEntry != null) {
// entity managed; return ID.
return pcEntry.getId();
}
}
final EntityPersister persister = resolveEntityPersister(entity, associationType, session, sessionFactory);
Serializable entityId = persister.getIdentifier(entity, session);
if (entityId == null) {
if (session != null) {
// if we have a session, then follow the HHH-11328 requirements
entityId = persistTransientEntity(entity, session);
}
// otherwise just let it be null HHH-11274
} else {
if (session != null) {
// if the entity is in the process of being merged, it may be stored in the
// PC already, but doesn't have an EntityEntry yet. If this is the case,
// then don't persist even if it is transient because doing so can lead
// to having 2 entities in the PC with the same ID (HHH-11328).
final EntityKey entityKey = session.generateEntityKey(entityId, persister);
if (session.getPersistenceContext().getEntity(entityKey) == null && ForeignKeys.isTransient(persister.getEntityName(), entity, null, session)) {
// entity is transient and it is not in the PersistenceContext.
// entity needs to be persisted.
persistTransientEntity(entity, session);
}
}
}
return entityId;
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class UnversionedCascadeDereferencedCollectionTest method testMergeNullCollection.
@Test
@TestForIssue(jiraKey = "HHH-9777")
public void testMergeNullCollection() {
Session s = openSession();
s.getTransaction().begin();
UnversionedCascadeOne one = new UnversionedCascadeOne();
assertNull(one.getManies());
s.save(one);
assertNull(one.getManies());
EntityEntry eeOne = getEntityEntry(s, one);
assertNull(eeOne.getLoadedValue("manies"));
s.flush();
assertNull(one.getManies());
assertNull(eeOne.getLoadedValue("manies"));
s.getTransaction().commit();
s.close();
final String role = UnversionedCascadeOne.class.getName() + ".manies";
s = openSession();
s.getTransaction().begin();
one = (UnversionedCascadeOne) s.merge(one);
// afterQuery merging, one.getManies() should still be null;
// the EntityEntry loaded state should contain a PersistentCollection though.
assertNull(one.getManies());
eeOne = getEntityEntry(s, one);
AbstractPersistentCollection maniesEEOneStateOrig = (AbstractPersistentCollection) eeOne.getLoadedValue("manies");
assertNotNull(maniesEEOneStateOrig);
// Ensure maniesEEOneStateOrig has role, key, and session properly defined (even though one.manies == null)
assertEquals(role, maniesEEOneStateOrig.getRole());
assertEquals(one.getId(), maniesEEOneStateOrig.getKey());
assertSame(s, maniesEEOneStateOrig.getSession());
// Ensure there is a CollectionEntry for maniesEEOneStateOrig and that the role, persister, and key are set properly.
CollectionEntry ceManiesOrig = getCollectionEntry(s, maniesEEOneStateOrig);
assertNotNull(ceManiesOrig);
assertEquals(role, ceManiesOrig.getRole());
assertSame(sessionFactory().getCollectionPersister(role), ceManiesOrig.getLoadedPersister());
assertEquals(one.getId(), ceManiesOrig.getKey());
s.flush();
// Ensure the same EntityEntry is being used.
assertSame(eeOne, getEntityEntry(s, one));
// Ensure one.getManies() is still null.
assertNull(one.getManies());
// Ensure CollectionEntry for maniesEEOneStateOrig is no longer in the PersistenceContext.
assertNull(getCollectionEntry(s, maniesEEOneStateOrig));
// Ensure the original CollectionEntry has role, persister, and key set to null.
assertNull(ceManiesOrig.getRole());
assertNull(ceManiesOrig.getLoadedPersister());
assertNull(ceManiesOrig.getKey());
// Ensure the PersistentCollection (that was previously returned by eeOne.getLoadedState())
// has key and role set to null.
assertNull(maniesEEOneStateOrig.getKey());
assertNull(maniesEEOneStateOrig.getRole());
// Ensure eeOne.getLoadedState() returns null for collection afterQuery flush.
assertNull(eeOne.getLoadedValue("manies"));
// Ensure the session in maniesEEOneStateOrig has been unset.
assertNull(maniesEEOneStateOrig.getSession());
s.getTransaction().commit();
s.close();
}
Aggregations