2017-12-18 224 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。
相关问题