6 Replies Latest reply on Mar 19, 2007 7:01 PM by Greg Zoller

    Dependent Fields in 2 Classes Best Practice?

    Greg Zoller Newbie

      Hello,

      For the purpose of this question assume I have 2 objects I'll show here extremely abbreviated and w/o all the annotations, but both are @Entity and all the persistence mappings work fine:

      public class Project {
       private List<Expense> expenses;
       private int spentAmt;
      
       public List<Expense> getExpenses() { return expenses; }
       public void setExpenses( List<Expense> expenses ) { this.expenses=expenses;}
      
       public int getSpentAmt() { return spentAmt; }
       public void setSpentAmt( int spentAmt ) { this.spentAmt = spentAmt; }
      }
      
      public class Expense {
       private Project proj;
       private int amt;
      }
      


      So I have a Project with its list of associated Expenses. Every time I add/change an expense I want to keep a running total in Project. I could just say spentAmt is @Transient and use a query to tally up all the expenses, but for the sake of conversation assume this would be an expensive process (e.g. lots of expenses and frequent access to spentAmt property) so I'd rather maintain a pre-computed sum.

      Are there any recommended ways keep this relationship between Project.spentAmt and Expense in sync, i.e. to know when an expense is truly initially created and edited (vs. just having its setters called upon marshalling the object from the db) so I can properly update Project.spentAmt?

      Here's what I have so far:

      * I can catch original creation by overriding persist() in ExpenseHome.
      * In Expense.setAmt() if I check whether proj is non-null (is Expense "wired"), it seems that it is not wired for marshalling, which I want to ignore, and is wired for edits, when I want to recompute Project.spentAmt.

      Are these observations safe assumptions or is there a better way?

      Thanks for any advice.
      Greg

        • 1. Re: Dependent Fields in 2 Classes Best Practice?
          Manuel Gombocz Newbie

          Hi Greg,

          I am not if it works, because I haven't tried it yet:

          Probably you could use the @javax.persistence.PrePersist and @javax.persistence.PreUpdate Callback Events in your Project Entity Bean for accumulating your expenses and then setting spentAmt.

          HTH,
          Manuel

          • 2. Re: Dependent Fields in 2 Classes Best Practice?
            Chuck Adams Novice

            You could take the suggestion of using persistence events to accumulate a running tally, but I would at most use such a total to update the UI with a "non-authoritative figure". Especially for financial data, you should only have one authoritative definition of any figure, and that should be from the only source that is guaranteed to have all the data, and that's the database. Your app might not be the only thing that ever updates the expenses tables in the future.

            You probably don't want to do the sums by fetching all the expense objects though, so you'd be best off with a scalar query, a raw sql query, or best yet, a stored procedure. It's going to be ridiculously fast in almost any database, and lends itself to optimizations like partitioning if you need it.

            • 3. Re: Dependent Fields in 2 Classes Best Practice?
              Greg Zoller Newbie

              Thanks for the feedback! Chuck's argument is hard to resist--best accurate data is using the db and using db logic the performance hit shouldn't be terrible.

              I've implemented a computed field using a @Formula annotation on the spentAmt's getter and this works great--almost.

              One problem: After I add an Expense (expense edit page) I redirect to my Project screen, but I still see the old calculated value for spentAmt. For some reason the new value reflecting my Expense addition isn't rendered. If I manually refresh the screen using the browser then I do get the correctly computed (new) values. Huh?

              Any idea why isn't my computed field being refreshed when the page is rendered?

              Thanks!

              • 4. Re: Dependent Fields in 2 Classes Best Practice?
                Siarhei Dudzin Apprentice

                May be you have another instance in the presentation view?

                • 5. Re: Dependent Fields in 2 Classes Best Practice?
                  Greg Zoller Newbie

                  It's possible but I don't think so. My debug page shows one projectHome component in the Application context and no conversations when the Project summary page is loaded.

                  I also determined that the getters that use the @Formula to compute the total in Project are being called (multiple times) during the screen render, even though the new results aren't appearing on the display.

                  I could be absolutely dead wrong, but since the getter is actually being called it feels like something in the UI has decided not to render the new result (until a hard-reload), and instead is using a cached value someplace.

                  Clues welcome...
                  Greg

                  • 6. Re: Dependent Fields in 2 Classes Best Practice?
                    Greg Zoller Newbie

                    I'll amend my last reply. When I'm in my Expense screen adding a new Expense there is a conversation running with a ProjectHome instance in it (presumably containing a Project instance). This context ends when I return to the Project screen.

                    Perhaps this is the instance being updated not whichever one is in the default context (which definitely does hold a Project instance somewhere)?

                    The problem remains though--how can I tell Seam I want to refresh/rerender the original Project? (If I nav away from the Project screen then return it renders the correct value--just not immediately after create/edit of an Expense.)