2017-12-18 225 views
0

我是新來的spring,同時從表中獲取記錄與其他表有關係得到這個懶洋洋的初始化錯誤。 我已經在網上閱讀了很多,但沒有得到適當的方法。未能在對象轉換爲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); 
} 

錯誤:

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: 

獲取異常而取對象轉換爲JSON。我發現由於代理對象返回由於提取類型懶惰(我想保持原樣)。

+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註釋具有fetch屬性,默認情況下該屬性設置爲LAZY。

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代之前,你應該出臺哪些初始化使用businessHour設置一個單獨的方法 同樣,Hibernate.initialize(terminal.getBusinessHour()) – PillHead

0

如果我reca這正是Entity在使用時從EntityManager中分離出來的一種錯誤(它是一個Proxy它無法執行數據庫查詢來檢索數據)。

您可以使用:

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

我不想使用fetchType急於 我們可以有其他的方式來做到這一點 – Rishabh

+0

爲什麼?幾乎沒有任何性能損失,而且您不必更復雜。 Imho這是一個更清潔的解決方案 – LppEdd

0

使用FetchType = EAGER意味着對你的實體的任何查詢將加載一大堆註明實體的。

Imho,如果您100%確定您的實體僅用於您的特殊業務案例,這只是一個明智的行爲。在所有其他情況下 - 比如將數據庫編程爲庫,或接受對實體的不同類型的查詢,您應該使用實體圖(https://docs.oracle.com/javaee/7/tutorial/persistence-entitygraphs002.htm)或顯式加載(Hibernate.initialize,join-fetch,請參閱示例https://vladmihalcea.com/hibernate-facts-the-importance-of-fetch-strategy/)。

如果您的使用情況下,僅是轉換,你有兩個很好的選擇:

  • 一個事務性方法內將您的實體JSON(如PillHead建議)
  • 與所有實體明確裝入實體在事務中需要(通過實體圖或Hibernate.initialize),然後在需要它的地方轉換爲JSON。
相關問題