下面列出了怎么用org.hibernate.engine.spi.EntityEntry的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
@Transactional(readOnly = true)
public List<Post> findAllByTitle(String title) {
List<Post> posts = postDAO.findByTitle(title);
org.hibernate.engine.spi.PersistenceContext persistenceContext = getHibernatePersistenceContext();
for(Post post : posts) {
assertTrue(entityManager.contains(post));
EntityEntry entityEntry = persistenceContext.getEntry(post);
assertNull(entityEntry.getLoadedState());
}
return posts;
}
/**
* entity id accessor
*
* @return The entity id
*/
public final Serializable getId() {
if ( id instanceof DelayedPostInsertIdentifier ) {
final EntityEntry entry = session.getPersistenceContext().getEntry( instance );
if ( entry == null ) {
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Skipping action - the persistence context does not contain any entry for the entity [%s]. This may occur if an entity is created and then deleted in the same transaction/flush.",
instance
);
}
// If an Entity is created and then deleted in the same Transaction, when Action#postDelete() calls this method the persistence context
// does not contain anymore an entry.
return null;
}
final Serializable eeId = entry.getId();
return eeId instanceof DelayedPostInsertIdentifier ? null : eeId;
}
return id;
}
/**
* process cascade save/update at the start of a flush to discover
* any newly referenced entity that must be passed to saveOrUpdate(),
* and also apply orphan delete
*/
private CompletionStage<Void> prepareEntityFlushes(EventSource session, PersistenceContext persistenceContext) throws HibernateException {
LOG.debug( "Processing flush-time cascades" );
CompletionStage<Void> stage = CompletionStages.nullFuture();
final IdentitySet copiedAlready = new IdentitySet( 10 );
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
for ( Map.Entry<Object, EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
stage = stage.thenCompose( v -> cascadeOnFlush( session, entry.getPersister(), me.getKey(), copiedAlready ) );
}
}
return stage;
}
/**
* Sets the target object to read-write, allowing Hibernate to dirty check it and auto-flush changes.
*
* @see #setObjectToReadyOnly(Object, org.hibernate.SessionFactory)
*
* @param target The target object
* @param sessionFactory The SessionFactory instance
*/
public static void setObjectToReadWrite(final Object target, SessionFactory sessionFactory) {
Session session = sessionFactory.getCurrentSession();
if (!canModifyReadWriteState(session, target)) {
return;
}
SessionImplementor sessionImpl = (SessionImplementor) session;
EntityEntry ee = sessionImpl.getPersistenceContext().getEntry(target);
if (ee == null || ee.getStatus() != Status.READ_ONLY) {
return;
}
Object actualTarget = target;
if (target instanceof HibernateProxy) {
actualTarget = ((HibernateProxy)target).getHibernateLazyInitializer().getImplementation();
}
session.setReadOnly(actualTarget, false);
session.setHibernateFlushMode(FlushMode.AUTO);
incrementVersion(target);
}
/**
* Custom deserialization routine used during deserialization of a
* Session/PersistenceContext for increased performance.
*
* @param ois The stream from which to read the entry.
* @param persistenceContext The context being deserialized.
*
* @return The deserialized EntityEntry
*
* @throws java.io.IOException If a stream error occurs
* @throws ClassNotFoundException If any of the classes declared in the stream
* cannot be found
*/
public static EntityEntry deserialize(
ObjectInputStream ois,
PersistenceContext persistenceContext) throws IOException, ClassNotFoundException {
String previousStatusString;
return new MutableEntityEntry(
persistenceContext.getSession().getFactory(),
(String) ois.readObject(),
(Serializable) ois.readObject(),
Status.valueOf( (String) ois.readObject() ),
( previousStatusString = (String) ois.readObject() ).length() == 0
? null
: Status.valueOf( previousStatusString ),
(Object[]) ois.readObject(),
(Object[]) ois.readObject(),
ois.readObject(),
LockMode.valueOf( (String) ois.readObject() ),
ois.readBoolean(),
ois.readBoolean(),
persistenceContext
);
}
@Override
public EntityEntry addEntity(
final Object entity,
final Status status,
final Object[] loadedState,
final EntityKey entityKey,
final Object version,
final LockMode lockMode,
final boolean existsInDatabase,
final EntityPersister persister,
final boolean disableVersionIncrement) {
addEntity( entityKey, entity );
return addEntry(
entity,
status,
loadedState,
null,
entityKey.getIdentifier(),
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement
);
}
private boolean updated(FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final Object entity = event.getEntity();
int[] dirtyProperties;
EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
SessionImplementor session = event.getSession();
if ( event.hasDatabaseSnapshot() ) {
dirtyProperties = persister.findModified( event.getDatabaseSnapshot(), values, entity, session );
}
else {
dirtyProperties = persister.findDirty( values, entry.getLoadedState(), entity, session );
}
return dirtyProperties != null;
}
@Override
public void replaceDelayedEntityIdentityInsertKeys(EntityKey oldKey, Serializable generatedId) {
final Object entity = entitiesByKey.remove( oldKey );
final EntityEntry oldEntry = entityEntryContext.removeEntityEntry( entity );
parentsByChild.clear();
final EntityKey newKey = session.generateEntityKey( generatedId, oldEntry.getPersister() );
addEntity( newKey, entity );
addEntry(
entity,
oldEntry.getStatus(),
oldEntry.getLoadedState(),
oldEntry.getRowId(),
generatedId,
oldEntry.getVersion(),
oldEntry.getLockMode(),
oldEntry.isExistsInDatabase(),
oldEntry.getPersister(),
oldEntry.isBeingReplicated()
);
}
@Override
@Transactional(readOnly = true)
public List<Post> findAllByTitle(String title) {
List<Post> posts = postDAO.findByTitle(title);
Session session = sessionFactory.getCurrentSession();
PersistenceContext persistenceContext = ((SharedSessionContractImplementor) session)
.getPersistenceContext();
for(Post post : posts) {
assertTrue(session.contains(post));
EntityEntry entityEntry = persistenceContext.getEntry(post);
assertNull(entityEntry.getLoadedState());
}
return posts;
}
/**
* PostLoad cannot occur during initializeEntity, as that call occurs *before*
* the Set collections are added to the persistence context by Loader.
* Without the split, LazyInitializationExceptions can occur in the Entity's
* postLoad if it acts upon the collection.
*
* HHH-6043
*
* @param entity The entity
* @param session The Session
* @param postLoadEvent The (re-used) post-load event
*/
public static void postLoad(
final Object entity,
final SharedSessionContractImplementor session,
final PostLoadEvent postLoadEvent) {
if ( session.isEventSource() ) {
final PersistenceContext persistenceContext
= session.getPersistenceContext();
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
postLoadEvent.setEntity( entity ).setId( entityEntry.getId() ).setPersister( entityEntry.getPersister() );
final EventListenerGroup<PostLoadEventListener> listenerGroup = session.getFactory()
.getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.POST_LOAD );
for ( PostLoadEventListener listener : listenerGroup.listeners() ) {
listener.onPostLoad( postLoadEvent );
}
}
}
@Override
public EntityEntry createEntityEntry(
Status status,
Object[] loadedState,
Object rowId,
Serializable id,
Object version,
LockMode lockMode,
boolean existsInDatabase,
EntityPersister persister,
boolean disableVersionIncrement,
PersistenceContext persistenceContext) {
return new MutableEntityEntry(
status,
loadedState,
rowId,
id,
version,
lockMode,
existsInDatabase,
persister,
disableVersionIncrement,
persistenceContext
);
}
private boolean updated(FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final Object entity = event.getEntity();
int[] dirtyProperties;
EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
SessionImplementor session = event.getSession();
if ( event.hasDatabaseSnapshot() ) {
dirtyProperties = persister.findModified( event.getDatabaseSnapshot(), values, entity, session );
}
else {
dirtyProperties = persister.findDirty( values, entry.getLoadedState(), entity, session );
}
return dirtyProperties != null;
}
protected boolean invokeInterceptor(
SessionImplementor session,
Object entity,
EntityEntry entry,
final Object[] values,
EntityPersister persister) {
boolean isDirty = false;
if ( entry.getStatus() != Status.DELETED ) {
if ( callbackRegistry.preUpdate( entity ) ) {
isDirty = copyState( entity, persister.getPropertyTypes(), values, session.getFactory() );
}
}
final boolean answerFromInterceptor = session.getInterceptor().onFlushDirty(
entity,
entry.getId(),
values,
entry.getLoadedState(),
persister.getPropertyNames(),
persister.getPropertyTypes()
);
return answerFromInterceptor || isDirty;
}
@Override
public LockMode getCurrentLockMode(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
if ( object == null ) {
throw new NullPointerException( "null object passed to getCurrentLockMode()" );
}
if ( object instanceof HibernateProxy ) {
object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation( this );
if ( object == null ) {
return LockMode.NONE;
}
}
EntityEntry e = persistenceContext.getEntry( object );
if ( e == null ) {
throw new TransientObjectException( "Given object not associated with the session" );
}
if ( e.getStatus() != Status.MANAGED ) {
throw new ObjectDeletedException(
"The given object was deleted",
e.getId(),
e.getPersister().getEntityName()
);
}
return e.getLockMode();
}
private Object[] getValues(Object entity, EntityEntry entry, boolean mightBeDirty, SessionImplementor session) {
final Object[] loadedState = entry.getLoadedState();
final Status status = entry.getStatus();
final EntityPersister persister = entry.getPersister();
final Object[] values;
if ( status == Status.DELETED ) {
//grab its state saved at deletion
values = entry.getDeletedState();
}
else if ( !mightBeDirty && loadedState != null ) {
values = loadedState;
}
else {
checkId( entity, persister, entry.getId(), session );
// grab its current state
values = persister.getPropertyValues( entity );
checkNaturalId( persister, entry, values, loadedState, session );
}
return values;
}
@Override
public Serializable getIdentifier(Object object) throws HibernateException {
checkOpen();
checkTransactionSynchStatus();
if ( object instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
if ( li.getSession() != this ) {
throw new TransientObjectException( "The proxy was not associated with this session" );
}
return li.getIdentifier();
}
else {
EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
throw new TransientObjectException( "The instance was not associated with this session" );
}
return entry.getId();
}
}
@Override
public String getEntityName(Object object) {
checkOpen();
// checkTransactionSynchStatus();
if ( object instanceof HibernateProxy ) {
if ( !persistenceContext.containsProxy( object ) ) {
throw new TransientObjectException( "proxy was not associated with the session" );
}
object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation();
}
EntityEntry entry = persistenceContext.getEntry( object );
if ( entry == null ) {
throwTransientObjectException( object );
}
return entry.getPersister().getEntityName();
}
/**
* process cascade save/update at the start of a flush to discover
* any newly referenced entity that must be passed to saveOrUpdate(),
* and also apply orphan delete
*/
private void prepareEntityFlushes(EventSource session, PersistenceContext persistenceContext) throws HibernateException {
LOG.debug( "Processing flush-time cascades" );
final Object anything = getAnything();
//safe from concurrent modification because of how concurrentEntries() is implemented on IdentityMap
for ( Map.Entry<Object,EntityEntry> me : persistenceContext.reentrantSafeEntityEntries() ) {
// for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries() ) ) {
EntityEntry entry = (EntityEntry) me.getValue();
Status status = entry.getStatus();
if ( status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY ) {
cascadeOnFlush( session, entry.getPersister(), me.getKey(), anything );
}
}
}
@Override
public boolean initializeLazyProperty(String fieldName, Object entity,
SharedSessionContractImplementor session,
EntityEntry entry,
int lazyIndex,
Object selectedValue) {
return super.initializeLazyProperty(fieldName, entity, session, entry, lazyIndex, selectedValue);
}
@Override
public boolean initializeLazyProperty(String fieldName, Object entity,
SharedSessionContractImplementor session,
EntityEntry entry,
int lazyIndex,
Object selectedValue) {
return super.initializeLazyProperty(fieldName, entity, session, entry, lazyIndex, selectedValue);
}
/**
* 1. detect any dirty entities
* 2. schedule any entity updates
* 3. search out any reachable collections
*/
private int flushEntities(final FlushEvent event, final PersistenceContext persistenceContext) throws HibernateException {
LOG.trace( "Flushing entities and processing referenced collections" );
final EventSource source = event.getSession();
final Iterable<FlushEntityEventListener> flushListeners =
source.getFactory().getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.FLUSH_ENTITY )
.listeners();
// Among other things, updateReachables() will recursively load all
// collections that are moving roles. This might cause entities to
// be loaded.
// So this needs to be safe from concurrent modification problems.
final Map.Entry<Object,EntityEntry>[] entityEntries = persistenceContext.reentrantSafeEntityEntries();
final int count = entityEntries.length;
for ( Map.Entry<Object,EntityEntry> me : entityEntries ) {
// Update the status of the object and if necessary, schedule an update
EntityEntry entry = me.getValue();
Status status = entry.getStatus();
if ( status != Status.LOADING && status != Status.GONE ) {
final FlushEntityEvent entityEvent = new FlushEntityEvent( source, me.getKey(), entry );
for ( FlushEntityEventListener listener : flushListeners ) {
listener.onFlushEntity( entityEvent );
}
}
}
source.getActionQueue().sortActions();
return count;
}
/**
* Generate an info message string relating to a particular managed
* collection. Attempts to intelligently handle property-refs issues
* where the collection key is not the same as the owner key.
*
* @param persister The persister for the collection
* @param collection The collection itself
* @param collectionKey The collection key
* @param session The session
* @return An info string, in the form [Foo.bars#1]
*/
public static String collectionInfoString(
CollectionPersister persister,
PersistentCollection collection,
Serializable collectionKey,
SharedSessionContractImplementor session ) {
StringBuilder s = new StringBuilder();
s.append( '[' );
if ( persister == null ) {
s.append( "<unreferenced>" );
}
else {
s.append( persister.getRole() );
s.append( '#' );
Type ownerIdentifierType = persister.getOwnerEntityPersister()
.getIdentifierType();
Serializable ownerKey;
// TODO: Is it redundant to attempt to use the collectionKey,
// or is always using the owner id sufficient?
if ( collectionKey.getClass().isAssignableFrom(
ownerIdentifierType.getReturnedClass() ) ) {
ownerKey = collectionKey;
}
else {
Object collectionOwner = collection == null ? null : collection.getOwner();
EntityEntry entry = collectionOwner == null ? null : session.getPersistenceContext().getEntry(collectionOwner);
ownerKey = entry == null ? null : entry.getId();
}
s.append( ownerIdentifierType.toLoggableString(
ownerKey, session.getFactory() ) );
}
s.append( ']' );
return s.toString();
}
private Object initializeLazyPropertiesFromCache(
final String fieldName,
final Object entity,
final SharedSessionContractImplementor session,
final EntityEntry entry,
final CacheEntry cacheEntry) {
LOG.trace( "Initializing lazy properties from second-level cache" );
Object result = null;
Serializable[] disassembledValues = cacheEntry.getDisassembledState();
final Object[] snapshot = entry.getLoadedState();
for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
final Serializable cachedValue = disassembledValues[lazyPropertyNumbers[j]];
final Type lazyPropertyType = lazyPropertyTypes[j];
final String propertyName = lazyPropertyNames[j];
if (cachedValue == LazyPropertyInitializer.UNFETCHED_PROPERTY) {
if (fieldName.equals(propertyName)) {
result = LazyPropertyInitializer.UNFETCHED_PROPERTY;
}
// don't try to initialize the unfetched property
}
else {
final Object propValue = lazyPropertyType.assemble(
cachedValue,
session,
entity
);
if ( initializeLazyProperty( fieldName, entity, session, snapshot, j, propValue ) ) {
result = propValue;
}
}
}
LOG.trace( "Done initializing lazy properties" );
return result;
}
/**
* Delete an object
*/
public void delete(Serializable id, Object version, Object object, SharedSessionContractImplementor session)
throws HibernateException {
final int span = getTableSpan();
boolean isImpliedOptimisticLocking = !entityMetamodel.isVersioned() && isAllOrDirtyOptLocking();
Object[] loadedState = null;
if ( isImpliedOptimisticLocking ) {
// need to treat this as if it where optimistic-lock="all" (dirty does *not* make sense);
// first we need to locate the "loaded" state
//
// Note, it potentially could be a proxy, so doAfterTransactionCompletion the location the safe way...
final EntityKey key = session.generateEntityKey( id, this );
Object entity = session.getPersistenceContext().getEntity( key );
if ( entity != null ) {
EntityEntry entry = session.getPersistenceContext().getEntry( entity );
loadedState = entry.getLoadedState();
}
}
final String[] deleteStrings;
if ( isImpliedOptimisticLocking && loadedState != null ) {
// we need to utilize dynamic delete statements
deleteStrings = generateSQLDeletStrings( loadedState );
}
else {
// otherwise, utilize the static delete statements
deleteStrings = getSQLDeleteStrings();
}
for ( int j = span - 1; j >= 0; j-- ) {
delete( id, version, j, object, deleteStrings[j], session, loadedState );
}
}
/**
* If there is already a corresponding proxy associated with the
* persistence context, return it; otherwise create a proxy, associate it
* with the persistence context, and return the just-created proxy.
*
* @param event The initiating load request event
* @param persister The persister corresponding to the entity to be loaded
* @param keyToLoad The key of the entity to be loaded
* @param options The defined load options
* @param persistenceContext The originating session
*
* @return The created/existing proxy
*/
private Object createProxyIfNecessary(
final LoadEvent event,
final EntityPersister persister,
final EntityKey keyToLoad,
final LoadEventListener.LoadType options,
final PersistenceContext persistenceContext) {
Object existing = persistenceContext.getEntity( keyToLoad );
if ( existing != null ) {
// return existing object or initialized proxy (unless deleted)
if ( traceEnabled ) {
LOG.trace( "Entity found in session cache" );
}
if ( options.isCheckDeleted() ) {
EntityEntry entry = persistenceContext.getEntry( existing );
Status status = entry.getStatus();
if ( status == Status.DELETED || status == Status.GONE ) {
return null;
}
}
return existing;
}
if ( traceEnabled ) {
LOG.trace( "Creating new proxy for entity" );
}
// return new uninitialized proxy
Object proxy = persister.createProxy( event.getEntityId(), event.getSession() );
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
persistenceContext.addProxy( keyToLoad, proxy );
return proxy;
}
private void handlePostUpdate(Object entity, EventSource source) {
EntityEntry entry = source.getPersistenceContext().getEntry( entity );
// mimic the preUpdate filter
if ( Status.DELETED != entry.getStatus()) {
callbackRegistry.postUpdate(entity);
}
}
public EntityEntry addReferenceEntry(
final Object entity,
final Status status) {
((ManagedEntity)entity).$$_hibernate_getEntityEntry().setStatus( status );
entityEntryContext.addEntityEntry( entity, ((ManagedEntity)entity).$$_hibernate_getEntityEntry() );
setHasNonReadOnlyEnties( status );
return ((ManagedEntity)entity).$$_hibernate_getEntityEntry();
}
@Override
public Object proxyFor(Object impl) throws HibernateException {
final EntityEntry e = getEntry( impl );
if ( e == null ) {
return impl;
}
return proxyFor( e.getPersister(), e.getEntityKey(), impl );
}
private void setEntityReadOnly(Object entity, boolean readOnly) {
final EntityEntry entry = getEntry( entity );
if ( entry == null ) {
throw new TransientObjectException( "Instance was not associated with this persistence context" );
}
entry.setReadOnly( readOnly, entity );
hasNonReadOnlyEntities = hasNonReadOnlyEntities || ! readOnly;
}
@Override
@Transactional
public Post findById(Long id) {
Post post = postDAO.findById(id);
org.hibernate.engine.spi.PersistenceContext persistenceContext = getHibernatePersistenceContext();
EntityEntry entityEntry = persistenceContext.getEntry(post);
assertNotNull(entityEntry.getLoadedState());
return post;
}