4

JSF検証フェーズで発生する問題に苦労しています.どういうわけか、その検証は休止状態が好きではないことを行っています(コレクションの遅延初期化に失敗し、セッションまたはセッションが閉じられませんでした)、何を理解したいですか? .

コンテキストは次のとおりです。多対多の関係で CheckType にリンクされているチェックがあります。私は既存のチェックを編集中です (その編集ページでは、特定のチェックタイプにリンクできるようにするために、多くのコンボボックスが提供されています)。

私もPrimefacesを使っています。

問題は検証プロセスの最後に発生しますが、私のコンバーターは正常に動作します (正しい結果を返します)。

さらに、これらすべてのオブジェクトが EAGER モードでロードされているのに、遅延が発生する理由がよくわかりません。

あなたの洞察に感謝します。私は静かに休止状態になり、それをJSFにもリンクしています:/

スタックトレース

11:15:08,137 INFO  [com.bdls.ids.utils.BDPhaseListener] (http-localhost-127.0.0.1-8080-3) Before PROCESS_VALIDATIONS 3
11:15:11,439 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 
11:15:11,440 INFO  [stdout] (http-localhost-127.0.0.1-8080-3)     select

11:15:11,486 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 
11:15:11,486 INFO  [stdout] (http-localhost-127.0.0.1-8080-3)     select

11:15:11,503 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 
11:15:11,504 INFO  [stdout] (http-localhost-127.0.0.1-8080-3)     select


11:15:12,942 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 
11:15:12,944 INFO  [stdout] (http-localhost-127.0.0.1-8080-3)     select

11:15:13,023 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 
11:15:13,023 INFO  [stdout] (http-localhost-127.0.0.1-8080-3)     select

11:15:13,040 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 

11:15:13,062 INFO  [stdout] (http-localhost-127.0.0.1-8080-3) Hibernate: 


11:15:13,856 WARNING [javax.enterprise.resource.webcontainer.jsf.lifecycle] (http-localhost-127.0.0.1-8080-3) failed to lazily initialize a collection, no session or session was closed: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:393) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:385) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:378) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at org.hibernate.collection.internal.PersistentSet.add(PersistentSet.java:206) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValuesForModel(MenuRenderer.java:382) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.convertSelectManyValue(MenuRenderer.java:129) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.renderkit.html_basic.MenuRenderer.getConvertedValue(MenuRenderer.java:315) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at org.primefaces.component.selectmanycheckbox.SelectManyCheckboxRenderer.getConvertedValue(SelectManyCheckboxRenderer.java:36) [primefaces-3.4.2.jar:]
    at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.validate(UIInput.java:960) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIInput.processValidators(UIInput.java:698) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIForm.processValidators(UIForm.java:253) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118) [jsf-impl-2.1.7-jbossorg-2.jar:]
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593) [jboss-jsf-api_2.1_spec-2.0.1.Final.jar:2.0.1.Final]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.primefaces.webapp.filter.FileUploadFilter.doFilter(FileUploadFilter.java:79) [primefaces-3.4.2.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at com.bdls.ids.controller.login.NoCacheFilter.doFilter(NoCacheFilter.java:39) [classes:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at com.bdls.ids.controller.login.AuthenticationFilter.doFilter(AuthenticationFilter.java:48) [classes:]
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:]
    at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.1.Final.jar:7.1.1.Final]
    at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final]
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:]
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:]
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:]
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:]
    at java.lang.Thread.run(Unknown Source) [rt.jar:1.6.0_32]

11:15:13,901 INFO  [com.bdls.ids.utils.BDPhaseListener] (http-localhost-127.0.0.1-8080-3) After PROCESS_VALIDATIONS 3

簡潔にするために興味深い部分だけを入れました:

Xhtml

<h:form id="new-items" prependId="false">
    <label for="typechecks">Type of checks :</label>
    <p:selectManyCheckbox id="typechecks" value="#{checksController.itemEdited.checkTypes}" layout="pageDirection" converter="checkTypeConverter">
        <f:selectItems value="#{checkTypeController.allItems}" var="checkType" itemLabel="#{checkType.name}" />
    </p:selectManyCheckbox>
<p:commandButton id="save" value="Save" action="#{checksController.persistItemEdited}" styleClass="btnFooterFormNewItems" icon="ui-icon-check" update="new-items" />

</h:form>

コンバータ

@FacesConverter("checkTypeConverter")
public class CheckTypeConverter implements Converter {

    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (value == null || value.toString().isEmpty()) {
            return ""; 
        }
        return ((UnversionedObject) value).getId().toString();
    }

    public Object getAsObject(FacesContext context, UIComponent arg1, String value) {

        CheckTypeService checkTypeService = FacesContextUtils.getWebApplicationContext(context).getBean("checkTypeService",
                CheckTypeService.class);
        return checkTypeService.getById(Integer.parseInt(value));
    }
}

コントローラ

@ManagedBean
@ViewScoped
public class ChecksController implements Serializable {
    private static Logger log = Logger.getLogger(ChecksController.class);

    // -------------------------------------------------
    // properties
    // -------------------------------------------------
    @ManagedProperty(value = "#{checksService}")
    private ChecksService checksService;

    // -------------------------------------------------
    // parameters
    // -------------------------------------------------
    private List<Check> allChecks;
    private Check[] selectedItem;
    private Check itemEdited = new Check();

    // -------------------------------------------------
    // constructor
    // -------------------------------------------------
    public ChecksController() {
        log.info("Creation of checks controller");

        allChecks = new ArrayList<Check>();

    }

    // -------------------------------------------------
    // methods
    // -------------------------------------------------
    @PostConstruct
    private void load() {
        if(FacesContext.getCurrentInstance().isPostback()) return;

        log.info("loading list of checks...");

        allChecks = checksService.getAll();
        log.info(String.format("Loaded %s items", allChecks.size()));
    }

    public void delete(Check c)
    {
        try{
            checksService.delete(c);
        }catch(Exception e){
            log.error("Error when deleting object "+c);
            e.printStackTrace();
        }
    }

    public void prefillFrom(String modelID) {
        log.info("Pre-filling based on model " + modelID);

        if (modelID == null) // new item
            return;

        // in this case, the item must exist (edition)
        itemEdited = checksService.getById(Integer.parseInt(modelID));
        if (itemEdited == null) {
            UINotification.sendAsError("Item does not exist", String.format("The item %s does not exist", modelID));
            log.error(String.format("The item %s does not exist", modelID));
        }
    }

    public void persistItemEdited(){
        log.info("persisting item edited...");

//      CheckType c = new CheckType();
//      c.setName("jolitest");
//      
//      itemEdited.getCheckTypes().add(c);
//      c.getChecks().add(itemEdited);
//      
        try{
            checksService.saveOrUpdate(itemEdited);
        }catch(Exception e){
            log.error("Error when saving object "+itemEdited);
            e.printStackTrace();
        }
        itemEdited = new Check() ;
    }

    public void test()
    {
        CheckType ct = new CheckType();
        ct.setName("toto");

        itemEdited.getCheckTypes().add(ct);


        Set<CheckType> set = new HashSet<CheckType>();
        set.add(ct);
        itemEdited.setCheckTypes(set);
    }

    getters and setters...

サービス

@Service("checksService")
@Transactional(readOnly = true)
public class ChecksServiceImpl implements ChecksService {
    @Autowired
    CheckDAO checkDAO;

    @Autowired
    CheckTypeDAO checkTypeDAO;

    /**
     * retrieves a UnversionedObject based on its id
     */
    public Check getById(Integer id) {
        return checkDAO.getById(id);
    }

    @Transactional(readOnly = false)
    public Check saveOrUpdate(Check c) {
        //for many-to-many relations, re-attach the entities
        if (c.getCheckTypes() != null && c.getCheckTypes().size() > 0)
        {
            List<CheckType> checkTypes = new ArrayList<CheckType>(c.getCheckTypes().size());
            for (CheckType ct : c.getCheckTypes()) {
                checkTypes.add(checkTypeDAO.getById(ct.getId()));
            }
            c.getCheckTypes().clear();
            c.getCheckTypes().addAll(checkTypes);
        }

        return checkDAO.saveOrUpdateDetached(c);
    }

    /**
     * returns a list of all checks
     */
    @Override
    public List<Check> getAll() {
        List<Check> list = checkDAO.getAll();
        return list;
    }

    /**
     * empty the extra relations and deletes the object
     */
    @Override
    @Transactional(readOnly = false)
    public void delete(Check c) {
        // attach object
        c = checkDAO.getById(c.getId());

        // initialize list
        Hibernate.initialize(c.getCheckTypes());

        // first remove relations to checktype
        c.getCheckTypes().clear();

        // update
        checkDAO.saveOrUpdateDetached(c);

        // now delete
        checkDAO.delete(c);
    }

}

DAO (実装)

@Repository
public class CheckDAOImpl extends BaseDAOimpl<Check> implements CheckDAO {

}

public abstract class BaseDAOimpl<T extends UnversionedObject> implements BaseDAO<T> {
    @Override
    public T saveOrUpdateDetached(T object) throws DataModelConsistencyException {
        updateUserAndTime(object);

        if (object.getId() != null) {
            return _entityManager.merge(object);
        } else {
            _entityManager.persist(object);
            return object;
        }
    }

rest omitted
}

小切手

@Entity
@Table(name = "IDS_SV_CHECK")
public class Check extends UnversionedObject {
    public static enum Severity {
        HIGH, MEDIUM, LOW, INFORMATIVE
    };

    @Column(length = 32)
    private String checkName;

    @Column
    private Integer subCheckID;

    @Enumerated(EnumType.STRING)
    private Severity severity;

    @Column(length = 32)
    private String description;

    @Column(length = 32)
    private String errorMsg;

    @Column(length = 32)
    private String DMVersion;

    @Column(length = 32)
    private String therapeuticArea;

    @ManyToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name = "IDS_SV_CHECK_HAS_TYPE",
                joinColumns={@JoinColumn(name="check_id")},
                inverseJoinColumns={@JoinColumn(name="checktype_id")})
    @BatchSize(size = 100)
    private Set<CheckType> checkTypes = new HashSet<CheckType>();
        ...

チェックタイプ

@Entity
@Table(name = "IDS_SV_CHECKTYPE")
public class CheckType extends UnversionedObject {

    @Column(length=60)
    private String name;

    @ManyToMany(mappedBy="checkTypes",fetch=FetchType.EAGER)
    private Set<Check> checks = new HashSet<Check>();
4

3 に答える 3

1

トランザクションの範囲外でアクティブな休止状態プロキシを使用してエンティティを返すことは絶対にしないでください。それは単に機能しません。Hibernateは、もはや存在しないトランザクションにバインドされているhibernateセッションにバインドされているコレクションのプロキシを作成しています。

可能な解決策:

1)オブジェクトを再取得する前に、常に休止状態のセッションからオブジェクトを切り離します

2)より過激な方法として、たとえばドーザーで作成したオブジェクトのコピーを常に返して、気付かない可能性のあるすべてのプロキシを削除します。

3)さらに過激で、コードをよりクリーンで理解しやすいものにする:1対nまたはn対nのリレーションシップを操作する必要がある場合は、@ OneToManyまたは@ManyToManyアノテーションを使用しないでください。そのような操作にDAOを提供し、常に明示的に読み取ります。 、挿入、更新、削除。IMHOは、理論的にはより多くのアプローチを必要とし、実践ではあなたのようなエラーと戦うためにより少ないアプローチを必要とする最善の解決策です。

于 2013-03-20T09:53:19.770 に答える
1

その理由は、バッキング Bean のライフサイクルが Spring に関連付けられていないためです。それを行う方法はありますが、以下はよりクリーンなアプローチです。

まず、Spring Boot Strap のデプロイメント記述子にリスナーがあることを確認してください

web.xml

<!-- Spring Bootstrap -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        a.package
        another.package
        some.other.package
    </param-value>
</context-param>

これで、コンテキストにアクセスするためのバッキング Bean (基本クラスの方が適切) のヘルパー メソッドが用意されました。

protected WebApplicationContext getContext()
{
    HttpServletRequest request = (HttpServletRequest) (FacesContext.getCurrentInstance().getExternalContext().getRequest());
    return WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext());
}

バッキング Bean で、次の方法で Spring Bean インスタンスにアクセスします。

ChecksService bean = getContext().getBean(ChecksService.class);

それは - あなたは行く準備ができているはずです。

于 2013-03-19T12:52:41.450 に答える