下面列出了怎么用org.hibernate.engine.spi.SelfDirtinessTracker的API类实例代码及写法,或者点击链接到github查看源代码。
@GET
@Path("model1")
@Transactional
public String testModel1() {
Assertions.assertEquals(0, Person.count());
Person person = makeSavedPerson();
SelfDirtinessTracker trackingPerson = (SelfDirtinessTracker) person;
String[] dirtyAttributes = trackingPerson.$$_hibernate_getDirtyAttributes();
Assertions.assertEquals(0, dirtyAttributes.length);
person.name = "1";
dirtyAttributes = trackingPerson.$$_hibernate_getDirtyAttributes();
Assertions.assertEquals(1, dirtyAttributes.length);
Assertions.assertEquals(1, Person.count());
return "OK";
}
@Override
public void postUpdate(Object entity, Object[] updatedState, Object nextVersion) {
this.loadedState = updatedState;
setLockMode( LockMode.WRITE );
if ( getPersister().isVersioned() ) {
this.version = nextVersion;
getPersister().setPropertyValue( entity, getPersister().getVersionProperty(), nextVersion );
}
if( entity instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
}
getPersistenceContext().getSession()
.getFactory()
.getCustomEntityDirtinessStrategy()
.resetDirty( entity, getPersister(), (Session) getPersistenceContext().getSession() );
}
@SuppressWarnings( {"SimplifiableIfStatement"})
private boolean isUnequivocallyNonDirty(Object entity) {
if ( entity instanceof SelfDirtinessTracker ) {
return ! persister.hasCollections() && ! ( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes();
}
final CustomEntityDirtinessStrategy customEntityDirtinessStrategy =
getPersistenceContext().getSession().getFactory().getCustomEntityDirtinessStrategy();
if ( customEntityDirtinessStrategy.canDirtyCheck( entity, getPersister(), (Session) getPersistenceContext().getSession() ) ) {
return ! customEntityDirtinessStrategy.isDirty( entity, getPersister(), (Session) getPersistenceContext().getSession() );
}
if ( getPersister().hasMutableProperties() ) {
return false;
}
return false;
}
private void addInLineDirtyHandling(CtClass managedCtClass) {
managedCtClass.addInterface( loadCtClassFromClass( SelfDirtinessTracker.class ) );
FieldWriter.addField(
managedCtClass,
loadCtClassFromClass( DirtyTracker.class ),
EnhancerConstants.TRACKER_FIELD_NAME
);
if ( collectCollectionFields( managedCtClass ).isEmpty() ) {
createDirtyTrackerMethodsWithoutCollections( managedCtClass );
}
else {
FieldWriter.addField(
managedCtClass,
loadCtClassFromClass( CollectionTracker.class ),
EnhancerConstants.TRACKER_COLLECTION_NAME
);
createDirtyTrackerMethodsWithCollections( managedCtClass );
}
}
private boolean isUpdateNecessary(final FlushEntityEvent event, final boolean mightBeDirty) {
final Status status = event.getEntityEntry().getStatus();
if ( mightBeDirty || status == Status.DELETED ) {
// compare to cached state (ignoring collections unless versioned)
dirtyCheck( event );
if ( isUpdateNecessary( event ) ) {
return true;
}
else {
if ( SelfDirtinessTracker.class.isInstance( event.getEntity() ) ) {
( (SelfDirtinessTracker) event.getEntity() ).$$_hibernate_clearDirtyAttributes();
}
event.getSession()
.getFactory()
.getCustomEntityDirtinessStrategy()
.resetDirty( event.getEntity(), event.getEntityEntry().getPersister(), event.getSession() );
return false;
}
}
else {
return hasDirtyCollections( event, event.getEntityEntry().getPersister(), status );
}
}
private void trackDirt(Object value, String propertyName, Object returnedValue) {
// value != returnedValue if either:
// 1) returnedValue was nullified (set to null);
// or 2) returnedValue was initialized, but not nullified.
// When bytecode-enhancement is used for dirty-checking, the change should
// only be tracked when returnedValue was nullified (1)).
if ( value != returnedValue && returnedValue == null
&& SelfDirtinessTracker.class.isInstance( self ) ) {
( (SelfDirtinessTracker) self ).$$_hibernate_trackChange( propertyName );
}
}
/**
* Prepares the save call using a newly generated id.
*
* @param entity The entity to be saved
* @param entityName The entity-name for the entity to be saved
* @param context Generally cascade-specific information.
* @param source The session which is the source of this save event.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected CompletionStage<Void> reactiveSaveWithGeneratedId(
Object entity,
String entityName,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
callbackRegistry.preCreate( entity );
if ( entity instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
}
EntityPersister persister = source.getEntityPersister( entityName, entity );
boolean autoincrement = persister.isIdentifierAssignedByInsert();
return generateId( entity, source, persister )
.thenCompose(id ->
reactivePerformSave(
entity,
autoincrement ? null : assignIdIfNecessary( id, entity, entityName, source ),
persister,
autoincrement,
context,
source,
!autoincrement || requiresImmediateIdAccess
)
);
}
private boolean isEnhanced(final Class<?> modifiedClass) {
Set<Class> interfaces = new HashSet<Class>(Arrays.asList(modifiedClass.getInterfaces()));
//Assert it now implements these three interfaces:
return interfaces.contains(ManagedEntity.class) &&
interfaces.contains(PersistentAttributeInterceptable.class) &&
interfaces.contains(SelfDirtinessTracker.class);
}
@Override
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
// moving to multiple fetch groups, the idea of `lazyPropertiesAreUnfetched` really
// needs to become either:
// 1) the names of all un-fetched fetch groups
// 2) the names of all fetched fetch groups
// probably (2) is best
//
// ultimately this comes from EntityEntry, although usage-search seems to show it is never updated there.
//
// also org.hibernate.persister.entity.AbstractEntityPersister.initializeLazyPropertiesFromDatastore()
// needs to be re-worked
if ( entity instanceof PersistentAttributeInterceptable ) {
final LazyAttributeLoadingInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata().extractInterceptor( entity );
if ( interceptor == null ) {
getEntityMetamodel().getBytecodeEnhancementMetadata().injectInterceptor( entity, session );
}
else {
if ( interceptor.getLinkedSession() == null ) {
interceptor.setSession( session );
}
}
}
// clear the fields that are marked as dirty in the dirtyness tracker
if ( entity instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
}
}
private void takeCollectionSizeSnapshot(Object target, String fieldName, Object value) {
if ( value != null && value instanceof Collection && target instanceof SelfDirtinessTracker ) {
CollectionTracker tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker();
if ( tracker == null ) {
( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes();
tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker();
}
tracker.add( fieldName, ( (Collection) value ).size() );
}
}
private void markInterceptorDirty(final Object entity, final Object target, EntityPersister persister) {
// for enhanced entities, copy over the dirty attributes
if ( entity instanceof SelfDirtinessTracker && target instanceof SelfDirtinessTracker ) {
// clear, because setting the embedded attributes dirties them
( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes();
for ( String fieldName : ( (SelfDirtinessTracker) entity ).$$_hibernate_getDirtyAttributes() ) {
( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( fieldName );
}
}
}
/**
* Prepares the save call using a newly generated id.
*
* @param entity The entity to be saved
* @param entityName The entity-name for the entity to be saved
* @param anything Generally cascade-specific information.
* @param source The session which is the source of this save event.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected Serializable saveWithGeneratedId(
Object entity,
String entityName,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
callbackRegistry.preCreate( entity );
if ( entity instanceof SelfDirtinessTracker ) {
( (SelfDirtinessTracker) entity ).$$_hibernate_clearDirtyAttributes();
}
EntityPersister persister = source.getEntityPersister( entityName, entity );
Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity );
if ( generatedId == null ) {
throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() );
}
else if ( generatedId == IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR ) {
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorHelper.POST_INSERT_INDICATOR ) {
return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess );
}
else {
// TODO: define toString()s for generators
if ( LOG.isDebugEnabled() ) {
LOG.debugf(
"Generated identifier: %s, using strategy: %s",
persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ),
persister.getIdentifierGenerator().getClass().getName()
);
}
return performSave( entity, generatedId, persister, false, anything, source, true );
}
}