-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 
Author Message
 Post subject: How should I deal with unreliable data?
PostPosted: Fri Jun 11, 2004 4:37 pm 
Newbie

Joined: Wed Jan 07, 2004 5:30 pm
Posts: 11
Location: SF, CA
Hi there,

I'm trying to deal with an issue that maybe some of you have run into, but I can't seem to find any previous forum discussions on the subject.

For the record this is using 2.1.4 on Oracle 8i.

My basic architecture is this:

I have a class called Channel which has a collection of Admins mapped as such:

Code:
<set name="admins" inverse="true" lazy="true" cascade="all-delete-orphan">
            <key column="CHANNEL_ID"/>
            <one-to-many class="foo.Admin"/>
        </set>


In turn, each Admin object has an Employee object:

Code:
<many-to-one
        name="employee"
        column="EMPLID"
        class="foo.Employee"/>


The Employee object is mapped to a materialized view of all the active employees in the company. This view gets refreshed nightly by a DB job, and employees that have been terminated disappear. Thus, I can't guarantee that an Employee exists for an Admin.

My problem is that when I load the Channel (which loads the collection of Admins), I get an UnresolvableObjectException, which is understandable.

My question is, how does one best handle this situation? I can't guarantee the consistency of Employee data, so should I write a custom type for Employee? Should I delve into the mysterious of the Lifecycle and Interceptor interfaces? Should I catch the exception, and if so, what do I do then -- will it just load a null object?

Any advice is appreciated. I'd be happy to share more code but I don't want to cloud the issue in a huge stack trace. Thanks in advance, Dolan


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 11, 2004 5:25 pm 
Newbie

Joined: Wed Jan 07, 2004 5:30 pm
Posts: 11
Location: SF, CA
Looking through the documentation again, I notice that a session.get() method was added at some point. This has the possible advantage over session.load() of not throwing an unrecoverable UnresolvableObjectException if the corresponding object can't be found, but loading a null, which (in my case) would be preferred as my view could deal with the problem.

As I noticed in my stack trace:

Code:
ERROR [http8080-Processor4] [2004-06-11 14:18:12,481] [foo.PeerBase]- getArticleList
net.sf.hibernate.UnresolvableObjectException: No row with the given identifier exists: 65354122131, of class: foo.Employee
        at net.sf.hibernate.UnresolvableObjectException.throwIfNull(UnresolvableObjectException.java:38)
        at net.sf.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1950)
        at net.sf.hibernate.type.ManyToOneType.resolveIdentifier(ManyToOneType.java:69)
        at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:204)
        at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2201)
        at net.sf.hibernate.loader.Loader.doQuery(Loader.java:240)
        at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:133)
        at net.sf.hibernate.loader.Loader.doList(Loader.java:955)
        at net.sf.hibernate.loader.Loader.list(Loader.java:946)
        at net.sf.hibernate.loader.SQLLoader.list(SQLLoader.java:92)
        at net.sf.hibernate.impl.SessionImpl.findBySQL(SessionImpl.java:3802)
        at net.sf.hibernate.impl.SQLQueryImpl.list(SQLQueryImpl.java:52)
        at foo.ArticlePeer.getArticleList(ArticlePeer.java:682)
        at foo.ArticlePeer.getInboxList(ArticlePeer.java:728)
        at foo.Article.getInboxList(Article.java:551)
        at foo.ArticleAction.list(ArticleAction.java:85)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:324)
        at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:280)
        at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:216)
        at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484)
        at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
        at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684)
        at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:432)
        at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:356)
        at org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1069)
        at org.apache.struts.tiles.TilesRequestProcessor.doForward(TilesRequestProcessor.java:274)
        at org.apache.struts.action.RequestProcessor.processForwardConfig(RequestProcessor.java:455)
        at org.apache.struts.tiles.TilesRequestProcessor.processForwardConfig(TilesRequestProcessor.java:320)
        at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:279)
        at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
        at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
        at foo.SecurityFilter.doFilter(SecurityFilter.java:77)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
        at foo.SessionFilter.doFilter(SessionFilter.java:65)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:213)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:551)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2422)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:163)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
        at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
        at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
        at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
        at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:199)
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:828)
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:700)
        at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:584)
        at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:683)
        at java.lang.Thread.run(Thread.java:534)


there is a Loader class that is, I would imagine, using the "load" method to do just that. I guess the question would be, for dependent objects, is there any way to specify that they be loaded using the "get" method? I realize that this could result in a storm of NPEs, but is there any other reason why this is either not feasible nor advisable?

Thanks again,
Dolan


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 11, 2004 7:00 pm 
Newbie

Joined: Wed Jan 07, 2004 5:30 pm
Posts: 11
Location: SF, CA
One more reply to myself...

I made a temporary solution; let me know if you think this is the right approach.

I made my Admin object (and any other object that contained an Employee) implement the Lifecycle interface.

I removed the Employee mapping from my objects completely, and instead mapped the Employee's key (emplID) as a scalar.

In the Admin object, using Lifecycle's onLoad() method, I now load the desired employee object(s). Since onLoad() is called after the parent object has been loaded, I already have the key which I need to load the dependent Employee object. For the Employee I use session.get() instead of session.load(), and voila, I have a null Employee object in the cases where the employee's id (emplID) doesn't correspond to any record. From there I handle any NPEs as one would expect.

Not beautiful, but it seems to work.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 11, 2004 7:02 pm 
Newbie

Joined: Wed Jan 07, 2004 5:30 pm
Posts: 11
Location: SF, CA
FWIW, here is the Lifecycle code for the Admin object now:

Code:
/**
     * Deal with volatile employee data by loading it using session.get() in
     * Employee DAO instead of mapping it directly.
     * PITA, but it works OK so far...
     *
     * @param s
     * @param id
     */
    public void onLoad(Session s, Serializable id) {
        if (this.emplid != null) {
            this.setEmployee(Employee.byEmplid(this.emplid));
        }
    };

    public boolean onSave(Session s) throws CallbackException {
        return true;
    };
    public boolean onUpdate(Session s) throws CallbackException {
        return true;
    };
    public boolean onDelete(Session s) throws CallbackException {
        return true;
    };


Top
 Profile  
 
 Post subject: Also on this issue
PostPosted: Mon Jun 13, 2005 12:18 pm 
Newbie

Joined: Mon Mar 01, 2004 3:41 pm
Posts: 9
Hi there,

i'm trying to solve the same problem, but mine is a little more tricky. i have an object Member which has a Member object called modifiedBy. In other words, the member record has a reference to another member record as the modifier of this member record.

So i can't get rid of the mapping for Member as you did for employee.

Either load or get would throw the UnresolvableObjectException when it comes to a bad record.

Does anyone have a new idea about what to do in this case?


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.