Re: strange DataContext? behaviour

From: martin ruff (mruf..imeon.ch)
Date: Fri Dec 13 2002 - 06:35:49 EST

  • Next message: Andrus Adamchik: "Re: strange DataContext? behaviour"

    Hi Craig,
    I FOUND the mistake !!!!
    it was a proplem in the datamap:
    all other object entities have a primary key definition:
    (I got those by reverse engineering the database)
    id integer PK mandatory maxlength 4

    projects had:
    id numeric PK mandatory

    now I changed it to:
    id integer PK mandatory maxlength 4

    and now it works:
    (Projects)theDataContext.registeredObject(new ObjectId(Projects.class,
    "id",projectsID.intValue()));
    now returns me a correct Projects object

    one question:
    maxlength, does this mean 4 digits?
    and if so, how is this enforced?
    cause I have entries with id's > 9999 ?
    for example in the auto_pk_support table for reportingdates the next id
    is 10100

    thanks again for your time and help
    martin

    Craig Miskell wrote:
    > 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 : Fri Dec 13 2002 - 06:35:32 EST