Java Code Examples for org.hibernate.NonUniqueObjectException

The following examples show how to use org.hibernate.NonUniqueObjectException. These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
/**
 * Performs the load of an entity.
 *
 * @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
 *
 * @return The loaded entity.
 */
private CompletionStage<Object> load( LoadEvent event, EntityPersister persister, EntityKey keyToLoad, LoadType options) {
	final EventSource session = event.getSession();
	if ( event.getInstanceToLoad() != null ) {
		if ( session.getPersistenceContextInternal().getEntry( event.getInstanceToLoad() ) != null ) {
			throw new PersistentObjectException(
					"attempted to load into an instance that was already associated with the session: " +
							MessageHelper.infoString( persister, event.getEntityId(), session.getFactory() ) );
		}
		persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), session );
	}

	return doLoad( event, persister, keyToLoad, options )
			.thenApply( optional -> {
				boolean isOptionalInstance = event.getInstanceToLoad() != null;
				if ( optional==null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
					throwEntityNotFound( session, event.getEntityClassName(), event.getEntityId() );
				}
				else if ( isOptionalInstance && optional != event.getInstanceToLoad() ) {
					throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
				}
				return optional;
			} );
}
 
Example 2
Source Project: TomboloDigitalConnector   Source File: SubjectUtils.java    License: MIT License 6 votes vote down vote up
public static void saveWithoutUpdate(List<Subject> subjects){
	HibernateUtil.withSession(session -> {
		session.beginTransaction();
		int saved = 0;
		for (Subject subject : subjects) {
               try{
                   session.save(subject);
                   saved++;
               }catch(NonUniqueObjectException e){
                   log.warn("Could not save subject {}, name {},", subject.getLabel(), subject.getName());
               }

			if ( saved % 50 == 0 ) {
				session.flush();
				session.clear();
			}
		}
		session.getTransaction().commit();
	});
}
 
Example 3
Source Project: TomboloDigitalConnector   Source File: TimedValueUtils.java    License: MIT License 6 votes vote down vote up
public static int save(List<TimedValue> timedValues){
	return HibernateUtil.withSession((session) -> {
		int saved = 0;
		session.beginTransaction();
		for (TimedValue timedValue : timedValues){
			try{
				session.saveOrUpdate(timedValue);
				saved++;
			}catch(NonUniqueObjectException e){
				// This is happening because the TFL stations contain a duplicate ID
				log.warn("Could not save timed value for subject {}, attribute {}, time {}: {}",
						timedValue.getId().getSubject().getLabel(),
						timedValue.getId().getAttribute().getDescription(),
						timedValue.getId().getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
						e.getMessage());
			}
			if ( saved % 50 == 0 ) { // because batch size in the hibernate config is 50
				session.flush();
				session.clear();
			}
		}
		session.getTransaction().commit();
		return saved;
	});
}
 
Example 4
Source Project: TomboloDigitalConnector   Source File: TimedValueUtils.java    License: MIT License 6 votes vote down vote up
public static int saveWithoutUpdate(List<TimedValue> timedValues){
	return HibernateUtil.withSession((session) -> {
		int saved = 0;
		session.beginTransaction();
		for (TimedValue timedValue : timedValues){
			try{
				session.save(timedValue);
				saved++;
			}catch(NonUniqueObjectException e){
				log.warn("Could not save timed value for subject {}, attribute {}, time {}: {}",
						timedValue.getId().getSubject().getLabel(),
						timedValue.getId().getAttribute().getDescription(),
						timedValue.getId().getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
						e.getMessage());
			}
			if ( saved % 50 == 0 ) { 
				session.flush();
				session.clear();
			}
		}
		session.getTransaction().commit();
		return saved;
	});
}
 
Example 5
Source Project: TomboloDigitalConnector   Source File: FixedValueUtils.java    License: MIT License 6 votes vote down vote up
public static int save(List<FixedValue> fixedValues){
    return HibernateUtil.withSession((session) -> {
        int saved = 0;
        session.beginTransaction();
        for (FixedValue fixedValue : fixedValues){
            try{
                session.saveOrUpdate(fixedValue);
                saved++;
            }catch(NonUniqueObjectException e){
                // This is happening because the TFL stations contain a duplicate ID
                log.warn("Could not save fixed value for subject {}, attribute {}: {}",
                        fixedValue.getId().getSubject().getLabel(),
                        fixedValue.getId().getAttribute().getLabel(),
                        e.getMessage());
            }
            if ( saved % 50 == 0 ) { // because batch size in the hibernate config is 50
                session.flush();
                session.clear();
            }
        }
        session.getTransaction().commit();
        return saved;
    });
}
 
Example 6
Source Project: TomboloDigitalConnector   Source File: FixedValueUtils.java    License: MIT License 6 votes vote down vote up
public static int saveWithoutUpdate(List<FixedValue> fixedValues){
    return HibernateUtil.withSession((session) -> {
        int saved = 0;
        session.beginTransaction();
        for (FixedValue fixedValue : fixedValues){
            try{
                session.save(fixedValue);
                saved++;
            }catch(NonUniqueObjectException e){
                log.warn("Could not save fixed value for subject {}, attribute {}: {}",
                        fixedValue.getId().getSubject().getLabel(),
                        fixedValue.getId().getAttribute().getLabel(),
                        e.getMessage());
            }
            if ( saved % 50 == 0 ) { 
                session.flush();
                session.clear();
            }
        }
        session.getTransaction().commit();
        return saved;
    });
}
 
Example 7
public void testPersistThenMergeInSameTxnWithVersion() {
	Session s = openSession();
	Transaction tx = s.beginTransaction();
	VersionedEntity entity = new VersionedEntity( "test", "test" );
	s.persist( entity );
	s.merge( new VersionedEntity( "test", "test-2" ) );

	try {
		// control operation...
		s.saveOrUpdate( new VersionedEntity( "test", "test-3" ) );
		fail( "saveOrUpdate() should fail here" );
	}
	catch( NonUniqueObjectException expected ) {
		// expected behavior
	}

	tx.commit();
	s.close();

	cleanup();
}
 
Example 8
public void testPersistThenMergeInSameTxnWithTimestamp() {
	Session s = openSession();
	Transaction tx = s.beginTransaction();
	TimestampedEntity entity = new TimestampedEntity( "test", "test" );
	s.persist( entity );
	s.merge( new TimestampedEntity( "test", "test-2" ) );

	try {
		// control operation...
		s.saveOrUpdate( new TimestampedEntity( "test", "test-3" ) );
		fail( "saveOrUpdate() should fail here" );
	}
	catch( NonUniqueObjectException expected ) {
		// expected behavior
	}

	tx.commit();
	s.close();

	cleanup();
}
 
Example 9
@Override
public void checkUniqueness(EntityKey key, Object object) throws HibernateException {
	final Object entity = getEntity( key );
	if ( entity == object ) {
		throw new AssertionFailure( "object already associated, but no entry was found" );
	}
	if ( entity != null ) {
		throw new NonUniqueObjectException( key.getIdentifier(), key.getEntityName() );
	}
}
 
Example 10
/**
 * Performs the load of an entity.
 *
 * @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
 *
 * @return The loaded entity.
 *
 * @throws HibernateException
 */
private Object load(
		final LoadEvent event,
		final EntityPersister persister,
		final EntityKey keyToLoad,
		final LoadEventListener.LoadType options) {

	if ( event.getInstanceToLoad() != null ) {
		if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
			throw new PersistentObjectException(
					"attempted to load into an instance that was already associated with the session: " +
							MessageHelper.infoString(
									persister,
									event.getEntityId(),
									event.getSession().getFactory()
							)
			);
		}
		persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession() );
	}

	final Object entity = doLoad( event, persister, keyToLoad, options );

	boolean isOptionalInstance = event.getInstanceToLoad() != null;

	if ( entity == null && ( !options.isAllowNulls() || isOptionalInstance ) ) {
		event.getSession()
				.getFactory()
				.getEntityNotFoundDelegate()
				.handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
	}
	else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
		throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
	}

	return entity;
}
 
Example 11
/**
 * Attempts to check whether the given key represents an entity already loaded within the
 * current session.
 * @param object The entity reference against which to perform the uniqueness check.
 * @throws HibernateException
 */
public void checkUniqueness(EntityKey key, Object object) throws HibernateException {
	Object entity = getEntity(key);
	if ( entity == object ) {
		throw new AssertionFailure( "object already associated, but no entry was found" );
	}
	if ( entity != null ) {
		throw new NonUniqueObjectException( key.getIdentifier(), key.getEntityName() );
	}
}
 
Example 12
/**
 * Perfoms the load of an entity.
 *
 * @return The loaded entity.
 * @throws HibernateException
 */
protected Object load(
	final LoadEvent event, 
	final EntityPersister persister, 
	final EntityKey keyToLoad, 
	final LoadEventListener.LoadType options)
throws HibernateException {

	if ( event.getInstanceToLoad() != null ) {
		if ( event.getSession().getPersistenceContext().getEntry( event.getInstanceToLoad() ) != null ) {
			throw new PersistentObjectException(
					"attempted to load into an instance that was already associated with the session: " +
					MessageHelper.infoString( persister, event.getEntityId(), event.getSession().getFactory() )
				);
		}
		persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), event.getSession().getEntityMode() );
	}

	Object entity = doLoad(event, persister, keyToLoad, options);
	
	boolean isOptionalInstance = event.getInstanceToLoad() != null;
	
	if ( !options.isAllowNulls() || isOptionalInstance ) {
		if ( entity == null ) {
			event.getSession().getFactory().getEntityNotFoundDelegate().handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
		}
	}

	if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
		throw new NonUniqueObjectException( event.getEntityId(), event.getEntityClassName() );
	}

	return entity;
}
 
Example 13
Source Project: AlgoTrader   Source File: HibernateUtil.java    License: GNU General Public License v2.0 5 votes vote down vote up
public static boolean lock(SessionFactory sessionFactory, Object target) {

		Session session = sessionFactory.getCurrentSession();

		try {
			session.buildLockRequest(LockOptions.NONE).lock(target);
			return true;
		} catch (NonUniqueObjectException e) {
			//  different object with the same identifier value was already associated with the session
			return false;
		}
	}
 
Example 14
Source Project: tutorials   Source File: HibernateExceptionUnitTest.java    License: MIT License 5 votes vote down vote up
@Test
public void givenSessionContainingAnId_whenIdAssociatedAgain_thenNonUniqueObjectException() {
    thrown.expect(isA(NonUniqueObjectException.class));
    thrown.expectMessage(
        "A different object with the same identifier value was already associated with the session");

    Session session = null;
    Transaction transaction = null;

    try {
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();

        Product product1 = new Product();
        product1.setId(1);
        product1.setName("Product 1");
        session.save(product1);

        Product product2 = new Product();
        product2.setId(1);
        product2.setName("Product 2");
        session.save(product2);

        transaction.commit();
    } catch (Exception e) {
        rollbackTransactionQuietly(transaction);
        throw (e);
    } finally {
        closeSessionQuietly(session);
    }
}
 
Example 15
/**
 * Prepares the save call by checking the session caches for a pre-existing
 * entity and performing any lifecycle callbacks.
 *
 * @param entity The entity to be saved.
 * @param id The id by which to save the entity.
 * @param persister The entity's persister instance.
 * @param useIdentityColumn Is an identity column being used?
 * @param context Generally cascade-specific information.
 * @param source The session from which the event originated.
 * @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> reactivePerformSave(
		Object entity,
		Serializable id,
		EntityPersister persister,
		boolean useIdentityColumn,
		C context,
		EventSource source,
		boolean requiresImmediateIdAccess) {

	if ( LOG.isTraceEnabled() ) {
		LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
	}

	final EntityKey key;
	if ( !useIdentityColumn ) {
		key = source.generateEntityKey( id, persister );
		final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
		Object old = persistenceContext.getEntity( key );
		if ( old != null ) {
			if ( persistenceContext.getEntry( old ).getStatus() == Status.DELETED ) {
				source.forceFlush( persistenceContext.getEntry( old ) );
			}
			else {
				return CompletionStages.failedFuture( new NonUniqueObjectException( id, persister.getEntityName() ) );
			}
		}
		persister.setIdentifier( entity, id, source );
	}
	else {
		key = null;
	}

	return reactivePerformSaveOrReplicate(
			entity,
			key,
			persister,
			useIdentityColumn,
			context,
			source,
			requiresImmediateIdAccess
	);
}
 
Example 16
/**
 * Construct a ActivationKeyCloneCommand
 * @param userIn user doing the cloning
 * @param key Activation key to be cloned
 * @param cloneDescription The description of the cloned key.
 */
public ActivationKeyCloneCommand(User userIn, String key,
        String cloneDescription) {

    ActivationKeyManager akm = ActivationKeyManager.getInstance();
    ActivationKey ak = lookupKey(key, userIn);

    try {
        cak = akm.createNewActivationKey(userIn, "", cloneDescription,
                ak.getUsageLimit(), ak.getBaseChannel(), false);
        // only one akey can be Universal default
    }
    catch (ValidatorException ve) { // the user is not allowed to create AK
        throw FaultException.create(1091, "activationkey", ve.getResult());
    }
    catch (NonUniqueObjectException e) {
        throw new ActivationKeyAlreadyExistsException();
    }

    // enable/disable
    cak.setDisabled(ak.isDisabled());

    // Entitlements
    Set<ServerGroupType> cloneEnt = new HashSet<ServerGroupType>();
    cloneEnt.addAll(ak.getEntitlements());
    cak.setEntitlements(cloneEnt);

    // child channels
    Set<Channel> channels = new HashSet<Channel>();
    channels.addAll(ak.getChannels());
    cak.setChannels(channels);

    // Configuration File Deployment
    cak.setDeployConfigs(ak.getDeployConfigs());

    // packages
    for (Iterator<TokenPackage> it = ak.getPackages().iterator(); it
            .hasNext();) {
        TokenPackage temp = it.next();
        cak.addPackage(temp.getPackageName(), temp.getPackageArch());
    }

    // Configuration channels
    List<String> lcloneConfigChannels = new ArrayList<String>();
    for (Iterator<ConfigChannel> it = ak.getConfigChannelsFor(userIn)
            .iterator(); it.hasNext();) {
        lcloneConfigChannels.add(it.next().getLabel());
    }

    List<String> lcak = new ArrayList<String>();
    lcak.add(cak.getKey());
    setConfigChannels(userIn, lcak, lcloneConfigChannels);

    // Groups
    Set<ServerGroup> cloneServerGroups = new HashSet<ServerGroup>();
    cloneServerGroups.addAll(ak.getServerGroups());
    cak.setServerGroups(cloneServerGroups);

    // Contact method
    cak.setContactMethod(ak.getContactMethod());
}
 
Example 17
/**
 * Prepares the save call by checking the session caches for a pre-existing
 * entity and performing any lifecycle callbacks.
 *
 * @param entity The entity to be saved.
 * @param id The id by which to save the entity.
 * @param persister The entity's persister instance.
 * @param useIdentityColumn Is an identity column being used?
 * @param anything Generally cascade-specific information.
 * @param source The session from which the event originated.
 * @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 performSave(
		Object entity,
		Serializable id,
		EntityPersister persister,
		boolean useIdentityColumn,
		Object anything,
		EventSource source,
		boolean requiresImmediateIdAccess) {

	if ( LOG.isTraceEnabled() ) {
		LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
	}

	final EntityKey key;
	if ( !useIdentityColumn ) {
		key = source.generateEntityKey( id, persister );
		Object old = source.getPersistenceContext().getEntity( key );
		if ( old != null ) {
			if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
				source.forceFlush( source.getPersistenceContext().getEntry( old ) );
			}
			else {
				throw new NonUniqueObjectException( id, persister.getEntityName() );
			}
		}
		persister.setIdentifier( entity, id, source );
	}
	else {
		key = null;
	}

	if ( invokeSaveLifecycle( entity, persister, source ) ) {
		return id; //EARLY EXIT
	}

	return performSaveOrReplicate(
			entity,
			key,
			persister,
			useIdentityColumn,
			anything,
			source,
			requiresImmediateIdAccess
	);
}
 
Example 18
/**
 * Ppepares the save call by checking the session caches for a pre-existing
 * entity and performing any lifecycle callbacks.
 *
 * @param entity The entity to be saved.
 * @param id The id by which to save the entity.
 * @param persister The entity's persister instance.
 * @param useIdentityColumn Is an identity column being used?
 * @param anything Generally cascade-specific information.
 * @param source The session from which the event originated.
 * @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 performSave(
		Object entity,
		Serializable id,
		EntityPersister persister,
		boolean useIdentityColumn,
		Object anything,
		EventSource source,
		boolean requiresImmediateIdAccess) {

	if ( log.isTraceEnabled() ) {
		log.trace(
				"saving " +
						MessageHelper.infoString( persister, id, source.getFactory() )
		);
	}

	EntityKey key;
	if ( !useIdentityColumn ) {
		key = new EntityKey( id, persister, source.getEntityMode() );
		Object old = source.getPersistenceContext().getEntity( key );
		if ( old != null ) {
			if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
				source.forceFlush( source.getPersistenceContext().getEntry( old ) );
			}
			else {
				throw new NonUniqueObjectException( id, persister.getEntityName() );
			}
		}
		persister.setIdentifier( entity, id, source.getEntityMode() );
	}
	else {
		key = null;
	}

	if ( invokeSaveLifecycle( entity, persister, source ) ) {
		return id; //EARLY EXIT
	}

	return performSaveOrReplicate(
			entity,
			key,
			persister,
			useIdentityColumn,
			anything,
			source,
			requiresImmediateIdAccess
	);
}
 
Example 19
@Test(expected = NonUniqueObjectException.class)
public void testAddAdd() {
    dao.add("uuid", "componentId", "contextId1");
    dao.add("uuid", "componentId", "contextId2");
}
 
Example 20
@Test(expected = NonUniqueObjectException.class)
public void testAddAdd() {
    dao.add("uuid", "componentId", "contextId1");
    dao.add("uuid", "componentId", "contextId2");
}
 
Example 21
/**
 * Construct a ActivationKeyCloneCommand
 * @param userIn user doing the cloning
 * @param key Activation key to be cloned
 * @param cloneDescription The description of the cloned key.
 */
public ActivationKeyCloneCommand(User userIn, String key,
        String cloneDescription) {

    ActivationKeyManager akm = ActivationKeyManager.getInstance();
    ActivationKey ak = lookupKey(key, userIn);

    try {
        cak = akm.createNewActivationKey(userIn, "", cloneDescription,
                ak.getUsageLimit(), ak.getBaseChannel(), false);
        // only one akey can be Universal default
    }
    catch (ValidatorException ve) { // the user is not allowed to create AK
        throw FaultException.create(1091, "activationkey", ve.getResult());
    }
    catch (NonUniqueObjectException e) {
        throw new ActivationKeyAlreadyExistsException();
    }

    // enable/disable
    cak.setDisabled(ak.isDisabled());

    // Entitlements
    Set<ServerGroupType> cloneEnt = new HashSet<ServerGroupType>();
    cloneEnt.addAll(ak.getEntitlements());
    cak.setEntitlements(cloneEnt);

    // child channels
    Set<Channel> channels = new HashSet<Channel>();
    channels.addAll(ak.getChannels());
    cak.setChannels(channels);

    // Configuration File Deployment
    cak.setDeployConfigs(ak.getDeployConfigs());

    // packages
    for (Iterator<TokenPackage> it = ak.getPackages().iterator(); it
            .hasNext();) {
        TokenPackage temp = it.next();
        cak.addPackage(temp.getPackageName(), temp.getPackageArch());
    }

    // Configuration channels
    List<String> lcloneConfigChannels = new ArrayList<String>();
    for (Iterator<ConfigChannel> it = ak.getConfigChannelsFor(userIn)
            .iterator(); it.hasNext();) {
        lcloneConfigChannels.add(it.next().getLabel());
    }

    List<String> lcak = new ArrayList<String>();
    lcak.add(cak.getKey());
    setConfigChannels(userIn, lcak, lcloneConfigChannels);

    // Groups
    Set<ServerGroup> cloneServerGroups = new HashSet<ServerGroup>();
    cloneServerGroups.addAll(ak.getServerGroups());
    cak.setServerGroups(cloneServerGroups);
}
 
Example 22
Source Project: aw-reporting   Source File: SqlReportEntitiesPersister.java    License: Apache License 2.0 4 votes vote down vote up
/**
 * Persists all the given entities into the DB configured in the {@code SessionFactory}. Specify
 * the following system properties backoff.delay
 */
@Override
@Transactional
@Retryable(
    value = {LockAcquisitionException.class},
    maxAttemptsExpression = "#{ @systemProperties['retryBackoff'] ?: 20}",
    backoff =
        @Backoff(
            delayExpression = "#{ @systemProperties['retryDelay'] ?: 100}",
            maxDelayExpression = "#{ @systemProperties['retryMaxDelay'] ?: 50000 }",
            multiplierExpression = "#{ @systemProperties['retryMultiplier'] ?: 1.5}"))
public void persistReportEntities(List<? extends Report> reportEntities) {
  int batchFlush = 0;
  Session session = sessionFactory.getCurrentSession();
  FlushMode previousFlushMode = session.getHibernateFlushMode();
  session.setHibernateFlushMode(FlushMode.MANUAL);

  try {
    for (Report report : reportEntities) {
      report.setRowId();

      session.saveOrUpdate(report);
      batchFlush++;

      if (batchFlush == config.getBatchSize()) {
        session.flush();
        session.clear();
        batchFlush = 0;
      }
    }

    if (batchFlush > 0) {
      session.flush();
      session.clear();
    }
  } catch (NonUniqueObjectException ex) {
    // Github issue 268 & 280
    //   https://github.com/googleads/aw-reporting/issues/268
    //   https://github.com/googleads/aw-reporting/issues/280
    //
    // Currently we allow specifying report definitions which do not include all primary key
    // fields. This leads to cryptic hibernate errors without providing a reasonable
    // resolution strategy.
    //
    // This fix explains where to find the list of primary key fields, but does not address
    // the underlying issue of allowing non-unique rows to be downloaded in the first place.
    //
    // Ideally we would guarantee uniqueness of rows without the user having to specify the
    // PK fields.
    // However, this would be a substantial migration for the AWReporting user base.
    // Instead, we just log a (hopefully) useful error message.
    // Also note that the error message assumes that reportEntities was not empty, because
    // otherwise the exception would not have been thrown.
    logger.error(
        "Duplicate row detected. This is most likely because your report definition does not "
            + "include the primary key fields defined in {}.setRowId(). "
            + "Please add the missing fields and try again.",
        reportEntities.get(0).getClass().getName());
    throw ex;
  } finally {
    session.setHibernateFlushMode(previousFlushMode);
  }
}