JPA 双向映射反复查询解决办法

EntitlementTransaction的结构:
@Entity
@Table(name = EntitlementTransactionConstant.TABLE_ENTITLEMENT_TRANSACTION)
public class EntitlementTransaction implements Serializable {
 
private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(generator = "system-uuid")
@Column(name = EntitlementTransactionConstant.GUID )
private String guid;

@Column(name = EntitlementTransactionConstant.TRANSACTIONID,nullable = false)
private String transactionID;

@Column(name = EntitlementTransactionConstant.ENTITLEMENTNAME)
private String entitlementName;

@Column(name = EntitlementTransactionConstant.TYPE)
private String type;

@Column(name = EntitlementTransactionConstant.TENANTID)
private long tenantID;

@Column(name = EntitlementTransactionConstant.CUSTOMER)
private String customer;

@Column(name = EntitlementTransactionConstant.STORAGE)
private long storage;

@Column(name = EntitlementTransactionConstant.CPUCORE)
private long cpuCore;

@Column(name = EntitlementTransactionConstant.USERCOUNT)
private long userCount;

@Column(name = EntitlementTransactionConstant.STATUS)
private String status;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = EntitlementTransactionConstant.ENTITLEMENTID)
private EntitlementMaster entitlementMaster ;


@Entity
@Table(name = EntitlementMasterConstant.TABLE_Master_Constant)
public class EntitlementMaster implements Serializable {


private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(generator = "system-uuid")
@Column(name = EntitlementMasterConstant.GUID)
private String guid;

@Column(name = EntitlementMasterConstant.ENTITLEMENTNAME)
private String entitlementName;

@Column(name = EntitlementMasterConstant.ENTITLEMENTGUID)
private String entitlementID;

@Column(name = EntitlementMasterConstant.TYPE)
private String type;

@Column(name = EntitlementMasterConstant.TENANTID)
private long tenantID;

@Column(name = EntitlementMasterConstant.CUSTOMER)
private String customer;

@Column(name = EntitlementMasterConstant.STORAGE)
private long storage;

@Column(name = EntitlementMasterConstant.CPUCORE)
private long cpuCore;

@Column(name = EntitlementMasterConstant.USERCOUNT)
private long userCount;

@Column(name = EntitlementMasterConstant.OPERANT)
private String Operant;

@OneToMany(mappedBy = "entitlementMaster", fetch = FetchType.LAZY,cascade = CascadeType.ALL)
private Set<EntitlementTransaction> entitlementTransaction = new HashSet<>();
EntitleMaster的结构:
@Entity
@Table(name = EntitlementMasterConstant.TABLE_Master_Constant)
public class EntitlementMaster implements Serializable {

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(generator = "system-uuid")
@Column(name = EntitlementMasterConstant.GUID)
private String guid;

@Column(name = EntitlementMasterConstant.ENTITLEMENTNAME)
private String entitlementName;

@Column(name = EntitlementMasterConstant.ENTITLEMENTGUID)
private String entitlementID;

@Column(name = EntitlementMasterConstant.TYPE)
private String type;

@Column(name = EntitlementMasterConstant.TENANTID)
private long tenantID;

@Column(name = EntitlementMasterConstant.CUSTOMER)
private String customer;

@Column(name = EntitlementMasterConstant.STORAGE)
private long storage;

@Column(name = EntitlementMasterConstant.CPUCORE)
private long cpuCore;

@Column(name = EntitlementMasterConstant.USERCOUNT)
private long userCount;

@Column(name = EntitlementMasterConstant.OPERANT)
private String Operant;

@OneToMany(mappedBy = "entitlementMaster", fetch = FetchType.LAZY,cascade = CascadeType.ALL)
private Set<EntitlementTransaction> entitlementTransaction = new HashSet<>();

这两张表通过EntitlementID字段来维持了双向映射的关系,在通过JPA对EntitlementTransaction表进行findALL()操作时,会因为这种双向映射关系导致反复查询同一条数据的情况,先来看数据库中的数据:

数据库中的数据

而查询出来的数据却是这样的:

查询出的数据

这个时候的Service层的代码是这样的:

@Autowired
EntitlementTransactionRepository entitlementTransactionRepository;
@Override
public List<EntitlementTransaction> getAll(){
    return  entitlementTransactionRepository.findAll();
}

如何解决这个问题呢?
首先新建EntitlementTransactionDtoNew类:

public class EntitlementTransactionDtoNew
{
private String guid;
private String entitlementID;
private String transactionID;
private String entitlementName;
private String type;
private long tenantID;
private String customer;
private long storage;
private long cpuCore;
private long userCount;
private String status;

getter and setter......
}

改写Service中的查询代码:

@Override
public List<EntitlementTransactionDtoNew> getAll(){
    List<EntitlementTransactionDtoNew> entitlementTransactionDtoNews = new ArrayList<>();
    for(EntitlementTransaction entitlementTransaction : entitlementTransactionRepository.findAll()){
        EntitlementTransactionDtoNew entitlementTransactionDto = new EntitlementTransactionDtoNew();
        entitlementTransactionDto.setGuid(entitlementTransaction.getGuid());
        entitlementTransactionDto.setEntitlementID(entitlementTransaction.getEntitlementMaster().getEntitlementID());
        entitlementTransactionDto.setTransactionID(entitlementTransaction.getTransactionID());
        entitlementTransactionDto.setEntitlementName(entitlementTransaction.getEntitlementName());
        entitlementTransactionDto.setType(entitlementTransaction.getType());
        entitlementTransactionDto.setTenantID(entitlementTransaction.getTenantID());
        entitlementTransactionDto.setCustomer(entitlementTransaction.getCustomer());
        entitlementTransactionDto.setStorage(entitlementTransaction.getStorage());
        entitlementTransactionDto.setCpuCore(entitlementTransaction.getCpuCore());
        entitlementTransactionDto.setUserCount(entitlementTransaction.getUserCount());
        entitlementTransactionDto.setStatus(entitlementTransaction.getStatus());
        
        entitlementTransactionDtoNews.add(entitlementTransactionDto);
    }
    return entitlementTransactionDtoNews;
}

通过这样的方式就可以打破双向映射导致的反复查询,于是我们得到如下的正确的findAll结果如图:

正确结果

这个问题是由JPA导致的,在同事的帮助下用这样的方式解决了该问题,希望JPA以后能够修复这个BUG。

推薦閱讀更多精彩內容