Prev: One Of The Easiest Ways To Promote Your Site!
Next: NegativeArraySizeException ... IndexOutOfBoundsException ...
From: Arved Sandstrom on 30 Dec 2009 16:43 Tom Anderson wrote: > On Tue, 29 Dec 2009, Lew wrote: > >> Lew wrote: >>>> Puzzle 1: Why are you explicitly allocating an ArrayList to >>>> 'objectsCfgSet'? >> >> kamiseq wrote: >>> why not? and plus you dont need to check every time if collection is >>> null or not. this is not a problem here >> >> Why not? Because it's atypical of JPA code and I haven't seen that >> done. Usually you either let the JPA engine fill it > > Which won't happen before the JPA provider has got its hands on it, so: > > new GenObject().objectsCfgSet.add(something); > > Will fail, right? > > There's a general principle (more honoured in the breach than in the > observance) that JPA entities should be fully functional POJOs, ie > should work correctly even without JPA. Or, perhaps, that they *can* be, > and since this simplifies unit testing, some pundits elevate that to > *should*. [ SNIP ] One area where you can have non-POJO behaviour is with the area I called out: lazy initialization. I've seen weird behaviour in some JPA implementations because of the various backing collections used in 1:n relationships, for example. Even if you call this misbehaviour defects - I would - it's still something to look out for with implementation of lazy initialization. Defects also appear in at least one implementation of cascades. You can always do without cascades so this is not a showstopper. And finally, with caching all bets are off. Your code will almost certainly behave differently in this respect for each JPA provider you try. AHS
From: Lew on 30 Dec 2009 20:58 Tom Anderson wrote: Lew wrote: >>>> Puzzle 1: Why are you explicitly allocating an ArrayList to >>>> 'objectsCfgSet'? kamiseq wrote: >>> why not? and plus you dont need to check every time if collection is >>> null or not. this is not a problem here Lew wrote: >> Why not? Because it's atypical of JPA code and I haven't seen that >> done. Usually you either let the JPA engine fill it Tom Anderson wrote: > Which won't happen before the JPA provider has got its hands on it, so: > > new GenObject().objectsCfgSet.add(something); > > Will fail, right? Well, duhh. You're supposed to pass in the List, not depend on it being there. That's why there's a setter for it. And it will certainly fail if 'objectsCfgSet' were properly declared as 'private'. > They're using setters because they're using property access - note the > @Id annotation on the getCustomerID() method rather than the id field. > That means they have to use setters to set fields. Kamiseq is using > field access, which means he can access the fields directly. There's no > JPA-specific reason for him to use a setter rather than direct access. There is a common idiom, universal to all the training literature on JPA, to have setters for even the collections. Furthermore, when you set up field-level annotations you still have bean patterns for the properties, and the variables remain 'private'. Your point does not apply. It's not that I think that initialization was wrong, necessarily. As I stated, it's atypical. Not one bit of training literature that I've read has done that, and not one bit of the JPA code I've worked with has, either. So it looked odd, and I wondered why he did it. A perfectly reasonable question, when you encounter an idiom that none of the experts use. Now I'm wondering why the OP took the question as an attack instead of a request for information. Anyway, once you persist the object, the initially-allocated List goes away and you lose control of whether it's null. So the point of not having to check if the collection is null doesn't apply, either. I think it's best to stick with the way JPA was designed, and I infer from the universal absence of collection initialization in the training literature that it was designed not to need it. I've seen what can happen to ORM code when it deviates from the intended idioms. You introduce epicycles that get ever more rococo. Entity objects are not really meant for a lot of manipulation outside the JPA context or by application logic. The more complicated you get with them, the weirder the behaviors you start to observe. I recommend not initializing the @OneToMany and @ManyToMany collections, but simply letting JPA do its job. As a rule. -- Lew
From: Arved Sandstrom on 30 Dec 2009 21:13 Lew wrote: [ SNIP ] > Anyway, once you persist the object, the initially-allocated List goes > away and you lose control of whether it's null. So the point of not > having to check if the collection is null doesn't apply, either. That's the main thing. Why bother assigning your own collection to a variable when JPA is going to completely ignore it. In a typical situation where you'd be creating a collection from scratch - namely, you've just created the parent so you know that there can't be any children, and you do have some children to persist at the same time, you'd typically set the new collection through the setter anyhow. > I think it's best to stick with the way JPA was designed, and I infer > from the universal absence of collection initialization in the training > literature that it was designed not to need it. I've seen what can > happen to ORM code when it deviates from the intended idioms. You > introduce epicycles that get ever more rococo. Entity objects are not > really meant for a lot of manipulation outside the JPA context or by > application logic. The more complicated you get with them, the weirder > the behaviors you start to observe. At the risk of beating a dead horse, I have observed that lazy initialization causes the most complications. I've learned to analyze usage and if it's clear that LAZY is situationally unnecessary, to not use it. Along the same lines I tend to to use cascades a lot less than I used to - they are just a coding convenience, and in reality come in useful a lot less than a person might think...but if haphazardly imposed on relationships "just in case", can cause problems. > I recommend not initializing the @OneToMany and @ManyToMany collections, > but simply letting JPA do its job. > > As a rule. Agreed. AHS P.S. I expect our "pure OOP, OODBMS roolz" friend to be frothing at the mouth just about now. :-)
From: Arved Sandstrom on 31 Dec 2009 11:28 kamiseq wrote: >> 1) The mappedBy name "objects" is jarring. If I understand you >> correctly, you're saying that for one GenObject we have many GenObjCnf >> objects. In the database the GenObjCnf table will have a foreign key for >> GenObject, and GenObjCnf is considered to be the owning side; GenObject >> is the inverse side, and has the mappedBy attribute, which you have >> correctly. "objects" is the field in each GenObjCnf that refers to the >> single GenObject, so would be something like >> >> GenObject genObject; >> >> and you'd more likely declare it as >> >> mappedBy="genObject" >> > sure but it was all auto generated by netbeans. NetBeans is pretty good at this, but it never hurts to review the generated code. Provided that what NB has generated fits in with my explanation above, you're cool. >> 4) do you know for a fact that after persisting that the DB is updated? >> Are you looking at console SQL or keeping an eye o the tables? What are >> your transactions like? Are you using application-managed or >> container-managed entity managers? >> > this all fine > >> 3) EntityManager.merge() doesn't update state - calling refresh() or >> explicitly changing state on the POJO instance does. >> >> 6) Lazy initialization is not pinned down by the JPA spec, leastways not >> JPA 1.0. Use at your own risk; persistence implementations have a lot of >> leeway. If you are newish to JPA, consider setting the OneToMany to >> EAGER (note that the default _is_ LAZY for that type of relationship, so >> you didn't need to put that in) and get stuff working. > > (ok but then it is a problem again with List collection - so I prefer > to stay with Lazy fetch) > > my question was more about why > > GenObject go = this.em.find(GenObject.class, object.getIdObject()); > GenObjectCfg parentCfg = go.getObjectsCfgSet().get(0); > > works fine (so all mappings between entities are correct and data in > DB is correct) where > > GenObject object = this.em.merge(object); > GenObjectCfg parentCfg = object.getObjectsCfgSet().get(0); > > is not working at all. (ok refreshing object this.em.refresh(object); > solves the problem and data is fetched). > > all I dont understand is - if my entity(GenObject) has lazily fetched > collection and it is detached from session then to start working with > that entity I need to first attach it to the session (em.merge()) This is correct. merge() is for bringing a detached entity back under management in a persistence context. As an aside, em.contains(entity) will tell you whether the context already has it managed...depending on whether you are using container-managed or application-managed EMs (and in the former case, whether you have transaction-scope or extended scope) it may well be that sometimes an entity is still managed when you may think that it's detached. Just something to keep in mind. > then > I can normally fetch the collection from the db, cannot I?for me it > doesn't matter how I obtain/create the entity(GenObject). I can > em.find that entity and return it to the client (entity's collection > is empty), the client wants to fetch more information about related > objects(GenObjectCfg) so the GenObject entity is sent back, merged and > I should be able to retrieve GenObjectCfg objects list without > refreshing GenObject. As an experiment (this is a fairly common trick) try calling size() on that lazy collection, see what it returns. AHS
From: kamiseq on 2 Jan 2010 12:29 > >>>> Puzzle 1: Why are you explicitly allocating an ArrayList to > >>>> 'objectsCfgSet'? > kamiseq wrote: > >>> why not? and plus you dont need to check every time if collection is > >>> null or not. this is not a problem here > It's not that I think that initialization was wrong, necessarily. As I > stated, it's atypical. Not one bit of training literature that I've read has > done that, and not one bit of the JPA code I've worked with has, either. cos it doesnt hurt :) in my application I am focused on collection itself. All I care about id if collection has 0 or more items. so if didn't initialize with ArrayList then there would be a situation when collection is null as JPA will not insert empty collection. from JPA and application point of view null reference is exactly the same as empty collection. but if collection is already there I don't need to check in my code for nulls. if you want to select, add or remove item or list items you need to be sure that collection is initialized. I still doesnt understand where this can be a problem and this is common pattern I and my friends apply
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 4 5 Prev: One Of The Easiest Ways To Promote Your Site! Next: NegativeArraySizeException ... IndexOutOfBoundsException ... |