Re: strange DataContext? behaviour

From: Craig Miskell (cmiskel..lbatross.co.nz)
Date: Fri Dec 13 2002 - 00:01:09 EST

  • Next message: martin ruff: "Re: strange DataContext? behaviour"

    Truly odd.

    When you say "with correct props HashMap", does that mean that the
    Projects has data at some stage, but not later on? My current guess is
    that the problem is some different section of code to what you've posted
    so far, possibly some unexpected side-effect of some call or other.

    I just checked, and the only place where the props hashmap is set is at
    object init time, and during deserialization. So unless you're
    deserializing and it's all going bad (unusual, because it deserializes
    into the HOLLOW state so it should fill itself in later), then I don't
    know what's happening.

    Are you setting the persistence state anywhere? Calling any other methods
    in DataContext?

    Craig

     On Fri, 13 Dec 2002, martin ruff wrote:

    > 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 - 23:59:33 EST