Re: strange DataContext? behaviour

From: martin ruff (mruf..imeon.ch)
Date: Thu Dec 12 2002 - 16:08:14 EST

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

    Hi Craig,

    >I'll assume that where you wrote:
    >newexpensesentry.ToExpensetype((...)
    >
    >you meant
    >newexpensesentry.setToExpensetype((...)
    >-----------------^^^

    oups, sorry, yes you're right I meant the above
    (newexpensesentry.setToExpensetype((...))

    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 - 16:08:00 EST