Spring Data JPARepository: How to conditionally fetch children entites

前端 未结 5 1367
余生分开走
余生分开走 2020-12-08 14:28

How can one configure their JPA Entities to not fetch related entities unless a certain execution parameter is provided.

According to Spring\'s documentation, 4.3.9

相关标签:
5条回答
  • 2020-12-08 14:54

    The lazy fetch should be working properly if no methods of object resulted from the getContacts() is called.

    If you prefer more manual work, and really want to have control over this (maybe more contexts depending on the use case). I would suggest you to remove contacts from the account entity, and maps the account in the contacts instead. One way to tell hibernate to ignore that field is to map it using the @Transient annotation.

    @Entity
    @Table(name = "accounts")
    public class Account
    {
        protected String accountId;
        protected Collection<Contact> contacts;
    
        @Transient
        public Collection<Contact> getContacts()
        {
            return contacts;
        }
    
        //getters & setters
    
    }
    

    Then in your service class, you could do something like:

    public Account getAccountById(int accountId, Set<String> fetchPolicy) {
        Account account = accountRepository.findOne(accountId);
        if(fetchPolicy.contains("contacts")){
            account.setContacts(contactRepository.findByAccountId(account.getAccountId());
        }
        return account;
    }
    

    Hope this is what you are looking for. Btw, the code is untested, so you should probably check again.

    0 讨论(0)
  • 2020-12-08 14:57

    If you are trying to send the resultset of your entities to a client, I recommend you use data transfer objects(DTO) instead of the entities. You can directly create a DTO within the HQL/JPQL. For example

    "select new com.test.MyTableDto(my.id, my.name) from MyTable my"
    

    and if you want to pass the child

    "select new com.test.MyTableDto(my.id, my.name, my.child) from MyTable my"
    

    That way you have a full control of what is being created and passed to client.

    0 讨论(0)
  • 2020-12-08 15:01

    Spring data does not ignore fetch=FetchType.Lazy.

    My problem was that I was using dozer-mapping to covert my entities to graphs. Evidently dozer calls the getters and setters to map two objects, so I needed to add a custom field mapper configuration to ignore PersistentCollections...

    GlobalCustomFieldMapper.java:

    public class GlobalCustomFieldMapper implements CustomFieldMapper 
    {
        public boolean mapField(Object source, Object destination, Object sourceFieldValue, ClassMap classMap, FieldMap fieldMapping) 
        {
           if (!(sourceFieldValue instanceof PersistentCollection)) {
                // Allow dozer to map as normal
                return;
            }
            if (((PersistentCollectiosourceFieldValue).wasInitialized()) {
                // Allow dozer to map as normal
                return false;
            }
    
            // Set destination to null, and tell dozer that the field is mapped
            destination = null;
            return true;
        }   
    }
    
    0 讨论(0)
  • 2020-12-08 15:02

    You can use @Transactional for that.

    For that you need to fetch you account entity Lazily.

    @Transactional Annotations should be placed around all operations that are inseparable.

    Write method in your service layer which is accepting one flag to fetch contacts eagerly.

    @Transactional
    public Account getAccount(String id, boolean fetchEagerly){
        Account account = accountRepository.findOne(id);
    
        //If you want to fetch contact then send fetchEagerly as true
        if(fetchEagerly){
            //Here fetching contacts eagerly
            Object object = account.getContacts().size();   
        }
    }
    

    @Transactional is a Service that can make multiple call in single transaction without closing connection with end point.

    Hope you find this useful. :)

    For more details refer this link

    0 讨论(0)
  • 2020-12-08 15:14

    Please find an example which runs with JPA 2.1.

    Set the attribute(s) you only want to load (with attributeNodes list) :

    Your entity with Entity graph annotations :

    @Entity
    @NamedEntityGraph(name = "accountGraph", attributeNodes = { 
      @NamedAttributeNode("accountId")})
    @Table(name = "accounts")
    public class Account {
    
        protected String accountId;
        protected Collection<Contact> contacts;
    
        @OneToMany(fetch=FetchType.LAZY)
        @JoinColumn(name="account_id", referencedColumnName="account_id")
        public Collection<Contact> getContacts()
        {
            return contacts;
        }
    }
    

    Your custom interface :

    public interface AccountRepository extends JpaRepository<Account, String> {
    
        @EntityGraph("accountGraph")
        Account findOne(String id);
    }
    

    Only the "accountId" property will be loaded eagerly. All others properties will be loaded lazily on access.

    0 讨论(0)
提交回复
热议问题