代码之家  ›  专栏  ›  技术社区  ›  adhg veen

hibernate envers-请求更改对象列表

  •  0
  • adhg veen  · 技术社区  · 6 年前

    我有一个 承包商 上面有 项目 他参与其中。合同还包含其他列表,如员工、付款和其他字段(名称、日期等)。

    我的目标是看看承包商与哪些项目相关。

    例子

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

    一天,用户从 主动的 完整的 等.

    所以现在每次我得到承包商的修改,我都会得到全部信息(项目、联系人、字段等)。问题是每次我接触项目(列表)时,它都会转到数据库。我的问题是,既然我需要对数据库做一点小小的改动,我如何才能只请求项目的修订?所以我可以告诉用户已经做了什么(例如:添加project x并标记project y的completion)

    到目前为止,我所做的是:

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

    我还试着只请求这样的项目(由于空指针异常而不起作用)

    ...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 回复  |  直到 6 年前
        1
  •  1
  •   Naros    6 年前

    根据你的评论 Project 不能 未指派的 从A Contractor 一旦链接完成,并且您只对与给定的 承包商 例如,获取相关信息的最佳方法可能是通过执行几个审计查询来构建该视图。

    你首先需要的是 项目 与之关联的ID 承包商 . 您可以从审计表中获取这些信息,但我认为最好直接从普通实体数据中获取这些信息。

    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();
    

    一旦获得了这些信息,就可以在循环中为每个 项目 以确定您需要的信息。

    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
    

    这里的关键是索引 我们将为您提供修改后的属性,因此您不必自己计算这些属性。