2017-12-18 9 views
0

私は春に新しく、他のテーブルとの関係を持つテーブルからレコードをフェッチしている間、この怠惰なイニシャルエラーが発生します。 私はオンラインで多くのことを読んだことがありますが、適切なアプローチを取っていません。オブジェクトのjsonへの変換中にロールのコレクションを遅延して初期化できませんでした

表1:

@SuppressWarnings("serial") 
@Entity 
public class Terminal extends BaseEntity { 

@Column(length = 100, unique = true) 
private String shortName; 

@Column 
private short number; // short stores up to 32767 value 

@Column 
private String description;  

@OneToMany 
@JoinColumn(name = "terminal_id", referencedColumnName = "uuid") 
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DELETE }) 
private Set<BusinessHour> businessHour; 

public String getShortName() { 
    return shortName; 
} 

public void setShortName(String shortName) { 
    this.shortName = shortName; 
} 

public short getNumber() { 
    return number; 
} 

public void setNumber(short number) { 
    this.number = number; 
} 

public String getDescription() { 
    return description; 
} 

public void setDescription(String description) { 
    this.description = description; 
} 
public Set<BusinessHour> getBusinessHour() { 
    return businessHour; 
} 

public void setBusinessHour(Set<BusinessHour> businessHour) { 
    this.businessHour = businessHour; 
} 

表2:

@SuppressWarnings("serial") 
@Entity 
public class BusinessHour extends BaseEntity { 

@Column 
private DayOfWeek dayOfWeek; 

@Column 
private LocalTime startOfOperation; 

@Column 
private LocalTime endOfOperation; 

public DayOfWeek getDayOfWeek() { 
    return dayOfWeek; 
} 
} 

サービスコード:

@Service 
public class TerminalServiceImpl implements TerminalService { 

@Autowired 
TerminalRepository terminalRepository; 


    Iterable<Terminal> allTerminals = terminalRepository.findAll(); 
    List<Terminal> terminalList = new ArrayList<Terminal>(); 
    for (Terminal terminal : allTerminals) { 
     terminalList.add(terminal); 
    } 
    return terminalList; 
} 

ターミナルリポジトリのコデ:

@Transactional 
public interface TerminalRepository extends CrudRepository<Terminal, Long> { 
} 

私は、デバッグ中にエラーが発生しましたコード:

private List<Terminal> updateTerminalList() { 
    List<Terminal> allTerminals = terminalService.fetchAllTerminal(); 
    return allTerminals; 
} 

public void terminalWrapperRun() { 
    try { 
     Payload payload = createTerminalPayload(applicationId); 
     String json3 = object2Json(payload); 
     kafkaRESTUtils.sendServerPayload(json3); 
    } catch (Exception e1) { 
     e1.printStackTrace(); 
    } 
} 

public String object2Json(Object dataArray) throws JsonProcessingException { 
    return mapper.writeValueAsString(dataArray); 
} 

エラー:JSONに取り出したオブジェクトを変換しながら

com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: terminal.model.Terminal.businessHour, could not initialize proxy - no Session (through reference chain: 

が例外を取得します。私はプロキシオブジェクトのリターン(私はそれを維持したい)フェッチタイプの遅延のために見つかった。

+0

可能性のある重複した[org.hibernate.LazyInitializationExceptionは:プロキシを初期化しないことができませんでした - 何のセッション?](https://stackoverflow.com/questions/22439306/org-hibernate-lazyinitializationexception-could-not-initialize-proxy -no-sessi) –

答えて

0

私は、この問題がデフォルトであなたのORMによってコレクションのLAZY読み込みに関係すると考えています。

@OneToMany 
@JoinColumn(name = "terminal_id", referencedColumnName = "uuid") 
@Cascade({ CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DELETE }) 
private Set<BusinessHour> businessHour; 

@OneToManyアノテーションには、デフォルトでLAZYに設定されているfetchプロパティがあります。

FetchType fetch() default LAZY; 

OneToMany reference

これは、データがアクセスされたとき、それが唯一ロードされることを意味します。あなたの例の場合、これはJSON文字列を作成しようとすると起こります。ただし、この時点では、ORMセッションの範囲外であるため、データのロード方法はわかりません。

したがって、2つの選択肢があります。

  1. 変更熱心BusinessHourセット親オブジェクトと同じ時間

    @OneToMany(フェッチ= FetchType.EAGER)

  2. でロードされることを意味する(データをロードするためにあなたのアノテーション(私は本当にこれが最初のオプションは、パフォーマンスの問題が発生していることをお勧めします)ORMセッション内で、あなたのJSON生成を行う。

+0

はどのように私はあなたが支援することができますORMセッション内でJSONを生成します。 – Rishabh

+1

提供されたコードを簡単に見てみると、これを実現する最も簡単な方法は、JSONを生成するメソッドの周りにTransactionalアノテーションを導入することです。これにより、必要なセッション内でコードが実行されます。私は、これはコードの誤解を招くような表現を与えるだろうと思うと述べました。おそらく、JSON生成を呼び出す前に、あなたは のHibernate.initialize(terminal.getBusinessHourを())を使用してbusinessHour設定を初期化する別の方法を導入すべきである – PillHead

0

Iの場合のRecAこれは、Entityが使用時にEntityManagerから切り離されたことによって発生する種類のエラーです(Proxyは、データを取得するためのデータベースクエリを実行できません)。

あなたは使用することができます。

@OneToMany(fetch = FetchType.EAGER) 
... 
private Set<BusinessHour> businessHour; 
+0

私はEAGER としてfetchTypeを使用したくない我々は – Rishabh

+0

なぜそれをする他の方法を持つことができます?そこはほとんどないパフォーマンスの低下であり、あなたも、より多くの事を複雑にする必要はありません。 Imhoはより洗練されたソリューションです – LppEdd

0

エンティティに対する任意のクエリは、注釈付きのエンティティの全体の束をロードしますFetchType = EAGER手段を使用。あなたのエンティティがあなたの特別なビジネスケースのためにのみ使用されることを100%確信している場合

私見では、これが唯一の賢明な行動です。

データアクセスをライブラリとしてプログラミングしたり、エンティティでさまざまな種類のクエリを受け入れるような場合は、エンティティグラフ(https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm)または明示的な読み込み(Hibernate.initialize、join-fetch、for例https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy/)。

ご利用の場合のみ、変換された場合、次の2つの良いオプションがあります。

  • をすべてのエンティティで明示的にエンティティをロード
  • (PillHeadが示唆したように)トランザクションメソッド内JSONにエンティティを変換しますトランザクション内(エンティティグラフやのHibernate.initialize経由)必要に応じ、その後、あなたがそれを必要とJSONに変換します。
関連する問題