简体   繁体   中英

Initializing many-to-many association in Hibernate with join table

I have a Company entity that I fetch with a JPQL query with Hibernate. The entity has a many-to-many association with a Keyword entity. Since the join table has an additional column is_active , this table has been mapped to a CompanyKeyword entity. So the association is like this:

Company <-- CompanyKeyword --> Keyword

Now, the association from the Company entity is lazy, and it is not initialized by my JPQL query, as I want to avoid creating a cartesian product performance problem. That is why I want to initialize the association after running the JPQL query, eg like this:

@Service
class CompanyServiceImpl implements CompanyService {
    @Autowired
    private CompanyRepository companyRepository;

    @Transactional
    public Company findOne(int companyId) {
        Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
        Hibernate.initialize(company.companyKeywords());
        return company;
    }
}

For a "normal" many-to-many association, this would work great, as all of the associated entities would be fetched in a single query. However, since I have an entity between Company and Keyword , Hibernate will only initialize the first part of the association , ie from Company to CompanyKeyword , and not from CompanyKeyword to Keyword . I hope that makes sense. I am looking for a way to initialize this association all the way without having to do something like this:

Company company = this.companyRepository.findOneWithSomeCustomQuery(companyId);
Hibernate.initialize(company.getCompanyKeywords());

for (CompanyKeyword ck : company.getCompanyKeywords()) {
    Hibernate.initialize(ck.getKeyword());
}

The above code is neither clean, nor good in terms of performance. If possible, I would like to stick to my current approach of using a JPQL query to fetch my Company entity and then initializing certain associations afterwards; it would take quite a bit of refactoring to change this in my project. Should I just "manually" fetch the association with a second JPQL query, or is there a better way of doing it that I haven't thought of?

Below are my mappings. Thanks in advance!

Company

@Entity
@Table(name = "company")
public class Company implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private int id;


    @Size(max = 20)
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "company")
    private Set<CompanyKeyword> companyKeywords = new HashSet<>();

    // Getters and setters
}

CompanyKeyword

@Entity
@Table(name = "company_service")
@IdClass(CompanyServicePK.class)
public class CompanyKeyword implements Serializable {
    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Company.class)
    @JoinColumn(name = "company_id")
    private Company company;

    @Id
    @ManyToOne(fetch = FetchType.LAZY, targetEntity = Keyword.class)
    @JoinColumn(name = "keyword_id")
    private Keyword keyword;

    @Column(nullable = true)
    private boolean isActive;


    // Getters and setters
}

CompanyKeywordPK

public class CompanyServicePK implements Serializable {
    private Company company;
    private Service service;

    public CompanyServicePK() { }

    public CompanyServicePK(Company company, Service service) {
        this.company = company;
        this.service = service;
    }

    // Getters and setters

    // hashCode()

    // equals()
}

Keyword

@Entity
@Table(name = "keyword")
public class Keyword {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private int id;

    // Fields and getters/setters
}

You'll indeed need to execute an additional JPQL query, fetching the company with its companyKeyWords and with the keyword of each CompanyKeyWord.

You could also doing it by simply looping and initializing every entity, and still avoid executing too many queries, by enabling batch fetching .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM