Spring Data JPARepository:如何有条件地获取子实体


问题内容

除非提供了某个执行参数,否则如何将其JPA实体配置为不获取相关实体。

根据Spring的文档4.3.9。配置Fetch-和LoadGraphs时,您需要使用@EntityGraph批注为查询指定获取策略,但是,这不能让我在运行时决定是否要加载这些实体。

我可以在一个单独的查询中获得子实体,但为此,我需要将自己的存储库或实体配置为不检索任何子实体。不幸的是,我似乎找不到任何有关执行此操作的策略。FetchPolicy将被忽略,并且EntityGraph仅在指定我要热切检索的实体时才有用。

例如,假设假定Account是父项,Contact是子项,并且一个帐户可以有多个联系人。

我希望能够做到这一点:

if(fetchPolicy.contains("contacts")){
  account.setContacts(contactRepository.findByAccountId(account.getAccountId());
}

问题是无论如何弹簧数据都急切地获取联系人。

Account Entity类如下所示:

@Entity
@Table(name = "accounts")
public class Account
{
    protected String accountId;
    protected Collection<Contact> contacts;

    @OneToMany
    //@OneToMany(fetch=FetchType.LAZY) --> doesn't work, Spring Repositories ignore this
    @JoinColumn(name="account_id", referencedColumnName="account_id")
    public Collection<Contact> getContacts()
    {
        return contacts;
    }

    //getters & setters

}

AccountRepository类如下所示:

public interface AccountRepository extends JpaRepository<Account, String>
{
    //@EntityGraph ... <-- has type= LOAD or FETCH, but neither can help me prevent retrieval
    Account findOne(String id);
}

问题答案:

如果没有调用由getContacts()导致的对象方法,则延迟获取应该正常工作。

如果您希望进行更多的人工工作,并且确实希望对此进行控制(根据使用情况,可能需要更多上下文)。我建议您从帐户实体中删除联系人,并将该帐户映射到联系人中。告诉hibernate状态忽略该字段的一种方法是使用@Transient批注对其进行映射。

@Entity
@Table(name = "accounts")
public class Account
{
    protected String accountId;
    protected Collection<Contact> contacts;

    @Transient
    public Collection<Contact> getContacts()
    {
        return contacts;
    }

    //getters & setters

}

然后在服务类中,您可以执行以下操作:

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;
}

希望这是您想要的。顺便说一句,该代码未经测试,因此您可能应该再次检查。