Hibernate Envers - запрос на изменение списка объектов - PullRequest
0 голосов
/ 07 июня 2018

У меня есть Подрядчик , у которого есть Список Проектов , с которыми он связан.Контракт также имеет другие списки, такие как Сотрудники, платежи и другие поля (имя, дата и т. Д.).

Моя цель - увидеть, какие проекты, с которыми связан подрядчик, были изменены.

пример

Contractor C is involved in the following projects: 
1. Furman street <Active>
2. Park West <Active> 
3. Central Train Station <Active>

однажды пользователь меняет проект Park West с Активный на завершен и т. Д.

Итактеперь каждый раз, когда я получаю ревизии Исполнителя, я получаю всю информацию (проекты, контакты, поля и т. д.).Проблема в том, что каждый раз, когда я касаюсь проектов (список) - он идет в БД.Мой вопрос, так как мне нужно сделать минимальное прикосновение к БД, как я могу запрашивать только ревизии проектов?так что я могу сказать, что сделал пользователь (пример: добавить проект X и отметить завершение для проекта Y)

Что я сделал до сих пор:

    AuditReader reader = AuditReaderFactory.get(em);
    AuditQuery query = reader.createQuery().forRevisionsOfEntity(Contractor.class, false, true).add(AuditEntity.id().eq(objID));

    List<Contractor> contractors = query.getResultList(); 

, и я также попыталсязапрашивать только такие проекты (не работали из-за исключения Null Pointer)

...add(AuditEntity.property("projects").hasChanged());




public class Contractor implements Serializable 
{
     //fields... name, dates... 

     @DiffIgnore
     @OneToMany(mappedBy = "contractor")
     @JsonIgnoreProperties(value = {"contractor"}, allowSetters=true)
     @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
     private Set<ContractorProject> projects = new HashSet<>();  //this is a many to many relationship for a reason 

}

1 Ответ

0 голосов
/ 07 июня 2018

На основании ваших комментариев, учитывая, что Project не может быть неназначенным из Contractor после того, как эта ссылка сделана, и что вы заинтересованы только в изменениях, внесенных в упомянутые проекты, связанные сДля данного экземпляра Contractor наилучшим способом получения рассматриваемой информации, вероятно, будет выполнение нескольких запросов аудита для построения этого представления.

Первое, что вам нужно, это список Project идентификаторов, которыесвязаны с этим Contractor.Вы можете получить эту информацию из таблиц аудита, но я полагаю, что было бы лучше просто получить ее непосредственно из данных обычных сущностей.

SELECT p.id FROM Contractor c JOIN c.projects p WHERE c.id = :contractorId

Вышеупомянутый запрос в основном является проекционным запросом, который даетидентификатор подрядчика, вы получаете все идентификаторы проекта, которые связаны с подрядчиком через ассоциацию проектов.

Если вы хотите получить это через таблицы аудита, первое, что нам нужно определить, этомаксимальный номер редакции для подрядчика, поэтому мы выбираем правильный снимок данных.

// you might want to check if this collection is empty
// it should not be assuming you aren't removing data from the audit tables
// but sometimes people archive data, so its best to be thorough
List<Number> revs = reader.getRevisions( Contractor.class, contractorId );

// The list of revisions are always in ascending order, so grab the last entry.
Number maxRevision = revs.get( revs.size() - 1 );

// Build the projection query
// This returns us the list of project ids, just like the HQL above
List projectIds = reader.createQuery()
   .forEntitiesAtRevision( Contractor.class, maxRevision )      
   .traverseRelation( "projects", JoinType.INNER )
   .addProjection( AuditEntity.property( "id" ).distinct() )
   .up()
   .add( AuditEntity.id().eq( contractorId ) )
   .getResultList();

Получив эту информацию, все сводится к выполнению запроса аудита в цикле для каждого Project, чтобы определить информациювам нужно.

for ( Object projectId : projectIds ) {
  List results = reader.createQuery()
     .forRevisionsOfEntity( Project.class, false, false )
     .add( AuditEntity.id().eq( projectId ) )
     .addOrder( AuditEntity.revisionNumber().asc() );
  // At this point you have an list of object array values 
  // Index 0 - This is the instance of Project 
  // Index 1 - This is the revision entity, you can get the rev # and timestamp
  // Index 2 - Type of revision, see RevisionType
  //
  // So you can basically iterate the list in ascending order keeping track of
  // the prior Project and build a changeset for each project.
  //
  // This approach is often more efficient if you're needing to compare multiple
  // attributes on an entity rather than issuing a query to the database for 
  // each change made to a single property.
}

В следующем основном выпуске Envers будут некоторые дополнительные методы запросов, которые позволят вам получить массив объектов, состоящий из следующих

  // Index 0 - This is the instance of Project 
  // Index 1 - This is the revision entity, you can get the rev # and timestamp
  // Index 2 - Type of revision, see RevisionType
  // Index 3 - Array of properties changed at this revision

Ключевым моментом здесь является индекс 3 , где мы предоставимУ вас есть свойства, которые были изменены, поэтому вам не нужно рассчитывать их самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...