Java Spring Data JPA - “无法初始化代理 - 没有会话” - 方法标记为事务性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36583185/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 18:27:33  来源:igfitidea点击:

Spring Data JPA - "could not initialize proxy - no Session" - With Methods marked as transactional

javahibernatespring-bootspring-data-jpac3p0

提问by douglasrlee

I have a model that has a pretty large graph of sub entities and hibernate ends up making around 9 statements to lazily fetch all of the data needed but about 4 levels deep I get a "could not initialize proxy - no Session" error and I am not sure why.

我有一个模型,它有一个相当大的子实体图,hibernate 最终做了大约 9 个语句来懒惰地获取所有需要的数据,但是大约 4 个级别深我得到一个“无法初始化代理 - 没有会话”错误,我是不知道为什么。

Controller

控制器

@Transactional(readOnly = true)
@RequestMapping(value = "/v2/plans", method = RequestMethod.GET)
public @ResponseBody List<PlanPresenter> show(HttpServletRequest request) throws Exception {
  List<PlanPresenter> planPresenters = new ArrayList<>();

  CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
  CriteriaQuery<Plan> planQuery = criteriaBuilder.createQuery(Plan.class);
  Root<Plan> root = planQuery.from(Plan.class);

  if (request.getParameter("region") != null || request.getParameter("group") != null) {
    List<Predicate> criteria = new ArrayList<Predicate>();
    if (request.getParameter("region") != null) {
      criteria.add(criteriaBuilder.equal(root.get(Plan_.region), request.getParameter("region")));
    }

    if (request.getParameter("group") != null) {
      criteria.add(criteriaBuilder.equal(root.get(Plan_.groupCode), request.getParameter("group")));
      criteria.add(root.get(Plan_.planSetId).in(groupPlanSetIds));
    } else {
      criteria.add(root.get(Plan_.planSetId).in(currentPlanSetIds));
    }

    Query query = entityManager.createQuery(planQuery.where(criteriaBuilder.and(criteria.toArray(new Predicate[]{}))));

    for (Plan plan : (List<Plan>)query.getResultList()) {
      planPresenters.add(new PlanPresenter(plan));
    }
  }

  return planPresenters;
}

Presenter

主持人

public class PlanPresenter {
  public String id;
  public String plan_set_id;
  public String region;
  public String name;
  public String description;
  public HashMap<String, Object> details = new HashMap<String, Object>();

  public PlanPresenter(Plan plan) throws Exception {
    this.id = String.valueOf(plan.id);
    this.plan_set_id = String.valueOf(plan.planSetId);
    this.region = plan.region.trim();
    this.name = plan.getName();
    this.description = plan.getDescription();

    this.details.put("spanish_plan", plan.isSpanishPlan());
    this.details.put("mutually_exclusive", plan.isMutuallyExclusive());
    this.details.put("group_plan", plan.isGroupPlan());
    this.details.put("group_code", plan.groupCode.trim());
    this.details.put("family_plan", plan.isFamilyPlan());
    this.details.put("price", plan.getPrice());
    this.details.put("enrollment_fee", plan.getEnrollmentFee());
    this.details.put("riders", plan.getRiders());
  }
}

Plan

计划

@Entity
public class Plan implements Serializable {
  private static final long serialVersionUID = 7639611964474770505L;

  private static List<String> familyPlanShortNames = Arrays.asList("ABCD");
  @Transient
  private String description = "";

  (Column definitions)

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
  @NotFound(action = NotFoundAction.IGNORE)
  public PlanDetail planDetail;

  @OneToMany(fetch = FetchType.LAZY)
  @JoinColumn(name = "XXXX", insertable = false, updatable = false, nullable = true)
  @OrderBy("XXXX")
  @NotFound(action = NotFoundAction.IGNORE)
  public List<Rider> riders;

  public String getName() {
    return this.planDetail != null ? this.planDetail.longName.trim() : null;
  }

  public Boolean isSpanishPlan() {
    return this.language.trim().equals("ES");
  }

  public Boolean isMutuallyExclusive() {
    return this.mutuallyExclusive.trim().equals("Y");
  }

  public Boolean isGroupPlan() {
    return this.groupCode != null && !this.groupCode.trim().equals("");
  }

  public Boolean isFamilyPlan() {
    return familyPlanShortNames.contains(this.planDetail.shortName.trim());
  }

  public BigDecimal getPrice() {
    return this.planDetail != null ? this.planDetail.price.setScale(2) : null;
  }

  public BigDecimal getEnrollmentFee() {
    return this.planDetail != null ? this.planDetail.enrollmentFee.setScale(2) : null;
  }

  public String getDescription() {
    if (this.planDetail != null && this.planDetail.brochureSections != null) {
      this.planDetail.brochureSections.forEach((brochureSection) -> {
        if (brochureSection.type.trim().equals("P1") && brochureSection.order == 1) {
          this.description = this.description + " " + brochureSection.text.trim();
        }
      });
    }

    return this.description.trim();
  }

  public List<HashMap<String, Object>> getRiders() {
    List<HashMap<String, Object>> riders = new ArrayList<HashMap<String, Object>>();
    if (this.riders != null && this.riders.size() > 0) {
      this.riders.forEach((rider) -> {
        HashMap<String, Object> planRider = new HashMap<String, Object>();
        planRider.put("name", rider.getName());
        planRider.put("price", rider.getPrice());
        planRider.put("description", rider.getDescription());
        riders.add(planRider);
      });
    }
    return riders;
  }
}

Plan Detail

计划详情

@Entity
public class PlanDetail implements Serializable {
  private static final long serialVersionUID = 2256881691562712018L;

  (Column definitions)

  @OneToMany(fetch = FetchType.LAZY)
  @JoinColumn(name = "XXXX", referencedColumnName = "XXXX", insertable = false, updatable = false, nullable = true)
  @OrderBy("XXXX")
  @NotFound(action = NotFoundAction.IGNORE)
  public List<BrochureSection> brochureSections;
}

Brochure Section

宣传册部分

@Entity
public class BrochureSection implements Serializable {
  private static final long serialVersionUID = 1856191232387921427L;

  (Column definitions)
}

Exception

例外

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.models.PlanDetail.brochureSections, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:576) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:215) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:555) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:143) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
at java.lang.Iterable.forEach(Iterable.java:74) ~[?:1.8.0_66]
at com.models.Plan.getDescription(Plan.java:100) ~[classes/:?]
at com.presenters.v2.PlanPresenter.<init>(PlanPresenter.java:20) ~[classes/:?]
at com.controllers.v2.PlansController.show(PlansController.java:64) ~[classes/:?]

Any help would be appreciated.

任何帮助,将不胜感激。

采纳答案by Joao Luiz Cadore

If you would like to keep Lazy Loadand you are using Spring Boot, just add the config below in your application.properties:

如果您想保持延迟加载并且您正在使用 Spring Boot,只需在application.properties 中添加以下配置:

spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true