31

私は小さなコンソールアプリケーションを持っていて、hibernateでspring-data-jpaを使用しています。スタンドアロンのコンソールアプリケーションでspring-data-jpaとそのリポジトリを使用するときに、コレクションを遅延初期化する方法を実際に理解することはできません。これが私のコードの一部です:

@Entity
public class User {
...
    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name="USER_ORDER_ID")
    private Set<Order> orders = new HashSet<Order>();
...
}

リポジトリ:

public interface UserRepository extends PagingAndSortingRepository<User, Long> {

    public ArrayList<User> findByFirstNameIgnoreCase(String firstName);
}

service impl:

@Service
@Repository
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

public ArrayList<User> findByFirstNameIgnoreCase(String firstName) {
    ArrayList<User> users = new ArrayList<User>();
    users = userRepository.findByFirstNameIgnoreCase(firstName);
    return users;
}

私の主な方法:

...
user = userRepository.findByFirstNameIgnoreCase("john").get(0);
orders = user.getOrders();
for (Order order : orders) {
  LOGGER.info("getting orders: " + order.getId());
}    

foreachループには例外があります。

EVERE:ロールのコレクションを遅延初期化できませんでした:com.aki.util.User.orders、セッションまたはセッションが閉じられていませんorg.hibernate.LazyInitializationException:ロールのコレクションを遅延初期化できませんでした:

ある種のOpenSessionInViewFilterを使用してWebアプリからこれを実行する場合、この問題は発生しないことに注意してください。

4

3 に答える 3

15

1つの解決策は、熱心にフェッチされたコレクションを作成するUser.ordersことです

@OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Order> orders = new HashSet<Order>();

エンティティの関連付けは、デフォルトで遅延ロードされます。これは、ordersSetが実際には単なるプロキシオブジェクトであり、メソッドを呼び出すまで初期化されないことを意味します。Order関連するオブジェクトは必要な場合を除いて読み込まれないため、これは適切です。ただし、実行中のトランザクションの外部で初期化されていないコレクションにアクセスしようとすると、問題が発生する可能性があります。

ほとんどの場合、ユーザーの注文が必要になることがわかっている場合は、関連付けを熱心に取得するのが理にかなっています。それ以外の場合は、コレクションがトランザクション内で初期化/ロードされることを確認する必要があります。あなたOpenSessionInViewFilterが言及したことは、リクエスト処理中にトランザクションが開いたままであることを確認します。そのため、youtwebappではこの問題は発生しません。

遅延ロードを維持する必要がある場合は、Springを使用TransactionTemplateしてメインメソッドでコードをラップしてみてください。

TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    @Override
    protected void doInTransactionWithoutResult(TransactionStatus status) {
    ...
    }
});
于 2013-02-18T14:58:18.667 に答える
9

しかし、私は方法を見つけました。このメソッドは私のサービス実装の中にあります:

public Set<Order> fetchUserOrders(Long userId) {
    User user = userRepository.findOne(userId);
    Hibernate.initialize(user.getOrders());
    Set<Order> orders = user.getOrders();
    return orders;
}

注:これは、@ zagyiが彼のコメントの1つで推測したとおりですが、ステートメントにも注意してください。Hibernate.initialize(user.getOrders());これがないと、コレクションは初期化されず、エラーが発生します。

于 2013-02-20T10:05:39.233 に答える
-2

これは私のために働いた:

@Component
public class Test {

    @Inject 
    OrderDAO orderDAO;

    @PersistenceUnit
    private EntityManagerFactory emf;

    @PostConstruct
    public void test(){
        EntityManager em= emf.createEntityManager();
        for (Order o:orderDAO.findAll()){
            o=em.find(o.getClass(),o.getId());
            System.out.println(o.getLazyField());
        }
        em.close();
    }
}
于 2013-08-07T00:42:42.060 に答える