This sounds more in line with what I was seeing.  I'll chip away at
it--coming up on the end of my testing cycle here.  The code patterns that
David showed me in Jan are paying big dividends now.

If I figure out a really solid way to do this (such as front-loading the
units ahead of time, which I think is a great idea), I'll see about drafting
up an example.

Cheers,
--
Alex





On Tue, Apr 22, 2008 at 12:33 PM, Dain Sundstrom <[EMAIL PROTECTED]> wrote:

> I ran into a strange behavior (strange in my mind) a while back that may
> be effecting your code.  Say you have the following code for Cheese
>
> public class Cheese {
>  private Long id; // auto generated pk
>  private String name;
>  public Cheese(String name) { this.name = name; }
>  public Long getId() { return id; }
>  public String getName() { return name; }
> }
>
>
> and a simple test
>
> public void test() {
>  Cheese wiz = new Cheese("wiz");
>  mgr.persist(wiz);
>  assertNotNull(wiz.getId());  // fails
> }
>
> The test will fail, because the id is not filled in until you flush and
> merge the instance.  Not the really, really, annoying thing is the merge
> returns a new instance of your object.  For example
>
> public void test() {
>  Cheese wiz = new Cheese("wiz");
>  mgr.persist(wiz);
>  mgr.flush();
>  Cheese persistentWiz = mgr.merge(wiz);
>  assertNotNull(persistentWiz.getId());
>  assertSame(wiz, persistentWiz); // fails
> }
>
> Anyway, unless you are updating your cache with the "merged" instance, the
> JPA system thinks you are attempting to create a new Cheese with the same
> name.  Assuming you changed your code to update, you will still run into
> problems when you have a multithreaded system.  The two transactions will
> likely want to use the same Unit (or Cheese in this case), the first one
> will persist and update and concurrent transaction will get a failure.  The
> easiest way to avoid these types of problems is to fill your Unit table
> ahead of time.  This is normally a reasonable requirement, as a business
> will only operate using one set of units (english vs. metric or a fixed set
> of allowed currencies), and typically the choice of of allowed units is made
> by a business person way ahead of time.  Alternatively, at runtime you can
> add units in a separate transaction.  You suspend the current tx, start a
> new one, create and persist the new unit, commit the tx, and resume the
> original tx.  The only drawback to that, is you don't get automatic rollback
> of the new unit.
>
> -dain
>
>
>
> On Apr 21, 2008, at 6:39 PM, Alexander Saint Croix wrote:
>
> > Thanks for the help, man.  I appreciate it.  The good news is that I
> > don't
> > have multiple instances of units with the same values.  I use a static
> > factory to build units (such as kilogram), and make them available via
> > public static references from an SI class.
> >
> > Forgetting units for a moment, let's say I have two entities.  Person
> > and
> > Cheese.  I provide a static reference "Cheeses.SWISS" to a pre-built
> > instance of Cheese with the "name" field of the instance set to "swiss".
> > Then, I create Person bob = new Person("Bob", Cheeses.SWISS) and call
> > mgr.persist(bob).
> >
> > In my case, I've got a cascading PERSIST relationship between Person and
> > Cheese.  So, after the transaction, Cheeses.SWISS has an ID value.
> >
> > Now, if I create Person alex = new Person("Alex", Cheeses.SWISS) and
> > pass it
> > to mgr.persist(alex), I get a funny error about the primary key field
> > already having a value (sorry, I don't have the exact error text, but
> > it's
> > easy to reproduce if it comes to that).
> >
> > I gather from this that this isn't the best way to introduce new objects
> > to
> > the persistence store when the objects reference data that is already in
> > the
> > store.  I'm guessing that instead of this, there should be some kind of
> > transaction that gets the Cheese object from the datastore and then adds
> > a
> > reference to it to the new Person object.  I think that pre-loading the
> > SI
> > units into the datastore at the beginning makes a lot of sense.  Now I
> > just
> > need some way to make sure that new entities that reference data already
> > in
> > the datastore are correctly wired.  I'm wondering if there are examples
> > of
> > this sort of thing?
> >
> > Cheers,
> > --
> > Alex
> >
> >
> >
> >
> > On Mon, Apr 21, 2008 at 12:21 PM, Dain Sundstrom <[EMAIL PROTECTED]> wrote:
> >
> >  I'm not sure I fully understand what you are running into, but I'll
> > > take a
> > > stab at it.
> > >
> > > Normally, I suggest people avoid storing unit tables in the db, but in
> > > your specific case, I know you are have a persistence model for a
> > > truly
> > > generic system.  BUT, for anyone else reading this email in the
> > > archives, be
> > > careful with unit tables as you can get nasty locking problems.
> > >
> > > In your case, I would suggest, if at all possible, that you create and
> > > cache your unit objects in a separate "setup" transaction.  After the
> > > setup
> > > transaction, no one would add new units (in a production system valid
> > > units
> > > would be added by hand by an admin), so you would never have a cascade
> > > persist problem.
> > >
> > > As for your exact situation, I think the root cause of the problem is
> > > that
> > > you have multiple instances with the same value, say kilogram, in your
> > > object graph.  If instead all references refereed to the same object
> > > instance, you the key would only be generated once.  To test my
> > > theory,
> > > replace the Unit constructor with a static factory, and cache the
> > > instances
> > > you return.
> > >
> > > -dain
> > >
> > >
> > > On Apr 20, 2008, at 8:57 AM, Alexander Saint Croix wrote:
> > >
> > >  Howdy, all.
> > > >
> > > > I'm wondering what the best practice is for the following use case:
> > > >
> > > > I have a handful of entity classes, one of which is a Unit (such as
> > > > "kilogram") which has an auto-generated UID field.  Each individual
> > > > instance
> > > > of Unit ("kilogram", "second", "ampere", etc) can and will be used
> > > > by
> > > > multiple instances of the other entity classes.
> > > >
> > > > The problem arises after I persist one of the unit instances (such
> > > > as
> > > > "kilogram") and it is assigned a primary key field generated by the
> > > > container.  From that point forward, each other object that refers
> > > > to
> > > > that
> > > > specific Unit instance gives me trouble when I try to persist it,
> > > > because it
> > > > already has a nonzero UID field value.
> > > >
> > > > Ideally, I do not want to have more than one "kilogram" record in
> > > > the
> > > > "Unit"
> > > > table.  Is there a common practice to tell the persistence container
> > > > to
> > > > "apply the persist cascade of the holding object to this field,
> > > > unless
> > > > the
> > > > data represented by the field already exists in the database, in
> > > > which
> > > > case
> > > > don't cascade--just reference the UID of that instance"?
> > > >
> > > > If the question isn't clear, I can provide sample code.  If you want
> > > > to
> > > > punt
> > > > to the OpenJPA list, that's also acceptable.
> > > >
> > > > Cheers,
> > > > --
> > > > Alex
> > > >
> > > >
> > >
> > >
>

Reply via email to