Re: strange DataContext? behaviour

From: martin ruff (mruf..imeon.ch)
Date: Thu Dec 12 2002 - 19:32:37 EST

  • Next message: Craig Miskell: "Re: strange DataContext? behaviour"

    Hi Craig,
    I did some more research:
    when I call
    newexpensesentry.getToProjects().getName()
    then somewhere in the framework the following method is called:

         protected Object readProperty(String propName) {
             if (persistenceState == PersistenceState.HOLLOW) {
                 dataContext.refetchObject(objectId);
             }

             return readPropertyDirectly(propName);
         }

    dataContext.refetchObject(objectId) returns actually a perfect Projects
    object, with correct props HashMap,

         public Object readPropertyDirectly(String propName) {
             return props.get(propName);
         }
    but then : props is an empty HashMap
    now I have to go to sleep its 2oclock in the morning
    thanks for your help so far, think were gonna get this one.
    greetings martin

    Craig Miskell wrote:
    > Glad to enlighten you regarding Hollow objects. This is a very odd
    > situation. It still looks to me like you're getting a hollow object
    > that's not getting filled in correctly, but I have no idea why! :-)
    >
    > You've obviously got DEBUG logging turned on (you say you see the
    > objects are updated and inserted properly). All I can suggest is that
    > you add your own logging statements at critical points: before/after
    > commits or anything else that might cause DB access, and specifically
    > right before you start accessing the Project properties that are
    > returning null (i.e. right before we'd expect a database access to fetch
    > the Project in question).
    >
    > Then run it and check the output. If nothing jumps out at you, e-mail
    > it to me and we'll see what we can make of it together.
    >
    > We'll figure this out eventually,
    >
    > Craig
    >
    > On Fri, 2002-12-13 at 10:08, martin ruff wrote:
    >
    >>Hi Craig,
    >
    >
    >>Oh thanks now I learned about "hollow" state
    >>I get the properties by the generated accessor methods:
    >>where newexpensesentry is the one after I inserted the values into the
    >>db and then got this one by running a new query
    >>String projectname = newexpensesentry.getToProjects().getName();
    >>which returns me null:
    >>String expenstype = newexpensesentry.getToExpensetype().getExpensetype();
    >>which returns me the expensetype, this works, and I set the ExpenseType
    >>exact the same way as the Project:
    >>((Expensetypes)theDataContext.registeredObject(new
    >> >> ObjectId(Expensetypes.class, "id",new Integer(1)))));
    >>If I do this with a new DataContext (not the same as I used to save the
    >>object) then everything works fine.
    >>Now I found out that i have the same behaviour regardless of if I create
    >>a new Expenses object and register it with the DataContext, fill set its
    >>properties and save it, or if I edit an existing one and the get the
    >>object back by a new SelectQuery, and again with a new DataContext it works
    >>
    >>her is the code with which I take n Expenses from a struts ActionFormBean
    >>the code does the following: it checks if it has to create a new
    >>Expenses object or edit an existing and the fills the values from the
    >>form, the caller of thes form then calls:
    >>theDataContext.commitChanges(Level.WARN);
    >>this works fine in the console window if my IDE (eclipse, this one's
    >>cool :-))) I can see that objects are updated and inserted according the
    >>data passed from the form
    >>
    >> public static void populateExpenses(ExpensesDataForm expensesdataform,
    >>DataContext theDataContext)
    >> {
    >> List expensesBOlist = expensesdataform.getExpensesBOsList();
    >> int sizebefore = expensesBOlist.size();
    >> for(int i = 0; i < expensesBOlist.size(); i++)
    >> {
    >> ExpensesBO theexpensesfromForm = (ExpensesBO)expensesBOlist.get(i);
    >> Expenses origexpenses = null;
    >> if(ApplicationConstants.NEWEXPENSES.equals(theexpensesfromForm.getID()))
    >> {
    >> if(!ApplicationConstants.NEWPROJECT.equals(new
    >>Integer(theexpensesfromForm.getSelectedProject())))
    >> {
    >> origexpenses =
    >>(Expenses)theDataContext.createAndRegisterNewObject("Expenses");
    >> origexpenses.setInvoiced(new
    >>BigDecimal(ApplicationConstants.ISNOTINVOICED));
    >> }
    >> }
    >> else
    >> {
    >> origexpenses = theexpensesfromForm.getTheExpense();
    >> }
    >> if(origexpenses != null)
    >> {
    >>
    >>origexpenses.setAmount(getBigDecimalFromString(theexpensesfromForm.getAmount()));
    >> origexpenses.setExpensedate(new java.sql.Date(
    >>DateFormatter.stringToDate_DDMMYYYY(theexpensesfromForm.getExpenseDate()).getTime()));
    >>
    >>origexpenses.setToEmployees(EmployeeService.findEmployeeByID(theDataContext,
    >>new Integer(expensesdataform.getUserWhoWantsToRapport())));
    >>
    >>origexpenses.setToExpensetype(ExpenseTypesService.findExpenseTypesByID(theDataContext,
    >>new Integer(theexpensesfromForm.getSelectedExpenseType())));
    >>
    >>origexpenses.setToProjects(ProjectsService.findProjectsByID(theDataContext,
    >>new Integer(theexpensesfromForm.getSelectedProject())));
    >>//theexpensesfromForm.getSelectedProject() returns me the correct
    >>//projectID of an existing project in DB, checked this in debugger
    >>origexpenses.setHours(getBigDecimalFromString(theexpensesfromForm.getHours()));
    >> origexpenses.setInvoicable( new BigDecimal(
    >>theexpensesfromForm.getInvoicable() ? ApplicationConstants.ISINVOICABLE
    >>: ApplicationConstants.ISNOTINVOICABLE));
    >> origexpenses.setNotice(theexpensesfromForm.getNotice());
    >>
    >>origexpenses.setNumberofkm(getBigDecimalFromString(theexpensesfromForm.getNumberofkm()));
    >>
    >>origexpenses.setToEmployeesResponsible(EmployeeService.findEmployeeByID(theDataContext,
    >>new Integer(expensesdataform.getUserWhoWantsToRapport())));
    >> //todo herausfinden, wer verantwortlich ist
    >> //origexpenses.setResponsible()
    >> }
    >> }
    >> }
    >>
    >>
    >>the findXXXbyID look all the same, here one as an example:
    >> public static Projects findProjectsByID(DataContext theDataContext,
    >>Integer projectsID)
    >> {
    >> return (Projects)theDataContext.registeredObject(new
    >>ObjectId(Projects.class, "ID",projectsID.intValue()));
    >> }
    >>
    >>here's the code whith which I get a list of Expenses (if I set the same
    >>time range as for the above inserted Expenses, which I do for testing)
    >>then I get the same objects as I inserted or updated above:
    >> public static List getExpenses4EmployeeInTimeFrame(DataContext
    >>theDataContext, Date beginDate, Date endDate, Employees theemployee)
    >> {
    >>
    >> Expression employeeidexpr = ExpressionFactory.binaryPathExp(
    >> Expression.EQUAL_TO,
    >> "ToEmployees",
    >> theemployee);
    >>
    >> Expression begindateexpr = ExpressionFactory. binaryPathExp(
    >> Expression.GREATER_THAN_EQUAL_TO,
    >> "expensedate",
    >> beginDate);
    >> Expression enddateexpr = ExpressionFactory.binaryPathExp(
    >> Expression.LESS_THAN_EQUAL_TO,
    >> "expensedate",
    >> endDate);
    >>
    >> employeeidexpr = employeeidexpr.andExp(begindateexpr).andExp(enddateexpr);
    >> SelectQuery query = new SelectQuery("Expenses", employeeidexpr);
    >> query.addOrdering("expensedate", true);
    >> return theDataContext.performQuery(query);
    >>
    >>This is the code which is running, thanks again for your time and have a
    >>nice day, greetings from cold switzerland
    >>martin
    >>
    >> >(If not, then that would be *very* interesting and maybe indicative of >a
    >> >problem).
    >> >
    >> >As to what the real problem may be:
    >> >Assuming that you are setting the toProjects in the same way as below
    >> >(obtaining it from theDataContext.registeredObject, by primary key),
    >> >then the object returned will be "hollow". The object (Project) will
    >> >not be fetched from the db until it's properties are read. So, the big
    >> >question is how are you reading it's properties? If you are using
    >> >readPropertyDirectly, then you are seeing expected behaviour....
    >> >readPropertyDirectly will not automatically fetch a HOLLOW object. You
    >> >have to use either readProperty (defined on CayenneDataObject rather
    >> >than DataObject), or the standard accessor methods (getTitle() etc.)
    >> >
    >> >If you are using the standard accessor methods, as generated by >Cayenne,
    >> >then something else strange is occuring. More code would help, if
    >> >you're permitted to send it (e-mail me privately if public distribution
    >> >is an issue).
    >>
    >> >Hope this (or something else) helps,
    >> >Craig Miskell
    >>
    >> >On Fri, 2002-12-13 at 07:03, martin ruff wrote:
    >> >> Hi I've got the following table
    >> >> CREATE TABLE expenses(
    >> >> id serial NOT NULL PRIMARY KEY,
    >> >> fk_employeeid int4 NOT NULL,
    >> >> fk_projectid int4 NOT NULL,
    >> >> expensedate date NOT NULL,
    >> >> fk_expensetype int4 NOT NULL,
    >> >> notice varchar(2000) NOT NULL,
    >> >> numberofkm numeric,
    >> >> hours numeric,
    >> >> amount numeric,
    >> >> invoicable numeric(1),
    >> >> invoiced numeric(1),
    >> >> responsible int4 NOT NULL,
    >> >> FOREIGN KEY (fk_employeeid) REFERENCES employees (id),
    >> >> FOREIGN KEY (fk_projectid) REFERENCES projects (id),
    >> >> FOREIGN KEY (fk_expensetype) REFERENCES expensetypes (id),
    >> >> FOREIGN KEY (responsible) REFERENCES employees (id));
    >> >>
    >> >> What I do:
    >> >> I create a new Expenses object and register it with DataContext:
    >> >> Expenses newexpensesentry =
    >> >> (Expenses)theDataContext.createAndRegisterNewObject("Expenses");
    >> >> then I fill all the values into that object I've defined relations >for
    >> >> the fk_.. references
    >> >>
    >> >> <obj-relationship name="ToEmployees" source="Expenses"
    >> >> target="Employees" toMany="false">
    >> >> <db-relationship-ref source="expenses" target="employees"
    >> >> name="ToEmployees"/>
    >> >> </obj-relationship>
    >> >> <obj-relationship name="ToEmployeesResponsible" source="Expenses"
    >> >> target="Employees" toMany="false">
    >> >> <db-relationship-ref source="expenses" target="employees"
    >> >> name="ToEmployeesResponsible"/>
    >> >> </obj-relationship>
    >> >> <obj-relationship name="ToExpensetype" source="Expenses"
    >> >> target="Expensetypes" toMany="false">
    >> >> <db-relationship-ref source="expenses" target="expensetypes"
    >> >> name="ToExpensetype"/>
    >> >> </obj-relationship>
    >> >> <obj-relationship name="ToProjects" source="Expenses" >target="Projects"
    >> >> toMany="false">
    >> >> <db-relationship-ref source="expenses" target="projects"
    >> >> name="ToProjects"/>
    >> >> </obj-relationship>
    >> >>
    >> >> then I set the refenrenced objects i.e.
    >> >>
    >> >>newexpensesentry.ToExpensetype((Expensetypes)theDataContext.registeredObject(new
    >> >> ObjectId(Expensetypes.class, "id",new Integer(1)))));
    >> >> I have the find the referenced object via it's primary key because
    >> >>from
    >> >> a web-interface I only get the primary key for the referenced object
    >> >>and
    >> >> not the object itself
    >> >> I do this for all the referenced objects:
    >> >> then I call theDataContext.commitChanges(Level.WARN);
    >> >> everything works fine, the problem comes now:
    >> >> If I get a list of expenses in a timerange (the Expense object
    >> >>inserted
    >> >> above is under the returned objects), then the newly created Expense
    >> >> objects I get in return from my query has an empty (properties are
    >> >> empty) Projects (relation ToProjects) objects related to it. The
    >> >>strange
    >> >> thing is, that the ExpenseType object that I get over the relation
    >> >> ToExpensetype is ok.
    >> >> If I create a NEW DataContext and rerun the query, again, everything
    >> >>is
    >> >> ok, also the Projects object thas had empty properties before.
    >> >> If I use THE SAME DataContext to insert a new Espense object and the
    >> >>run
    >> >> the query I get problems as described above.
    >> >> Has anyone a idea what the problem could be here?
    >> >> thanks in advance
    >> >> martin
    >> >>
    >>
    >>
    >



    This archive was generated by hypermail 2.0.0 : Thu Dec 12 2002 - 19:32:54 EST