reset password
Author Message
aligh1979
Posts: 121
Posted 12:13 Oct 28, 2011 |

1-in this example , how is the phone_order done? entity manager automatically put some sort of int  value in this field on the database side (we do not have any real field on the class side to represent this column) . if yes , how the order gets its priorities , assume that we have a form that has 10 inputs to enter different phone numbers , then the first one automatically gets the highest priority and the last one the lowest?

@ElementCollection

@OrderColumn(name = “phone_order”)

List<String> phones;

 

2- the other thing is that , there is no extra query required for getting these phones back for one customer ? as long as we have the annotation like above , it should be able to access to it ?.  just say "return List <String> customer.phones  "  ?

Last edited by aligh1979 at 12:48 Oct 28, 2011.
cysun
Posts: 2935
Posted 13:35 Oct 28, 2011 |

1. Yes. The order of the phones in the database is the same as in the Java list.

2. Yes, you can use customer.getPhone() to retrieve the phones if you already have the customer object.

aligh1979
Posts: 121
Posted 00:35 Oct 29, 2011 |

my current design for my collection type " -score " -  seems correct , I even looked at some other csns classes  , and some online sources. but when I am running TestNg it gives me this error . I have taken a snapshot of the error message.  error happens when I call something like "rubricScore.getScores"   ....

adding "Transactional" to the Dao file did not help either

Failed to Lazily initialize a collection.......  No session or session was closed.

Attachments:
Last edited by aligh1979 at 00:50 Oct 29, 2011.
aligh1979
Posts: 121
Posted 00:57 Oct 29, 2011 |

I found the solution myself . the trick is to add "(fetch = FetchType.EAGER)" after the @ElementCollection

like this .   @ElementCollection(fetch = FetchType.EAGER)


--------------------------------------

had to do this for both Rubric and Criteria to make it work

Last edited by aligh1979 at 02:10 Oct 29, 2011.
aligh1979
Posts: 121
Posted 01:21 Oct 29, 2011 |

The only thing that I am not able to figure out is that it returns one extra NULL value , I even checked the table , there is no empty cell nor is NULL value.

just tested it for criterias , and as soon as it reaches the collection object (Descriptions for each criteria) it returns one extra Null value for index 0 and the rest of the real results after that .

the other thing is that because each Rubric has Criteria and each criteria has a collection object of rate description , when we make a Rubric object and try to reach the criteria property of it , the size of criteria is , the actual size of criteria (size of List<Criteria>) * (times)  size of rate Description or rubric scale (List<description>). it is like joining between Criteria and rate Description table(rate description has duplicate Criteria id / "as joincolumn" ) .which returns multiple of Criteria objects . which makes sense if we just were doing a simple join in sql , but not for an object property.

better explanation is that the number of criteria are 3 here and each criteria has 3 rate description fields . it returns the criteria size for a rubric 9 = 3*3

so whether I am doing something wrong or there should be a better way around this

Last edited by aligh1979 at 12:55 Oct 29, 2011.
cysun
Posts: 2935
Posted 22:47 Oct 29, 2011 |

1. The Lazy Initialization error can be solved by changing the test class to inherit from AbstractTransactionalTestNGSpringContextTests instead of AbstractTestNGSpringContextTests. This makes each test method run in a transaction so Spring will keep the entity manager open until a method finishes.

2. The second problem regarding the extra null is probably caused by a wrong index in an order column. In fact I had the same problem in my csns-test-insert.sql script:

insert into instructors (section_id, instructor_id, instructor_order) values (1000300, 1000, 1);
insert into instructors (section_id, instructor_id, instructor_order) values (1000301, 1000, 1);

should be changed to:

insert into instructors (section_id, instructor_id, instructor_order) values (1000300, 1000, 0);
insert into instructors (section_id, instructor_id, instructor_order) values (1000301, 1000, 0);

The index of a List starts from 0. In the old code Hibernate would add a null at index 0 of the List.

3. I'm not sure what caused your third problem: wrong size of criteria. There's probably something wrong with your mapping.

aligh1979
Posts: 121
Posted 23:21 Oct 29, 2011 |

So we should not use the "@ElementCollection(fetch = FetchType.EAGER  )" ?

Last edited by aligh1979 at 23:22 Oct 29, 2011.
cysun
Posts: 2935
Posted 23:25 Oct 29, 2011 |
aligh1979 wrote:

So we should not use the "@ElementCollection(fetch = FetchType.EAGER  )" ?

Do you want to eagerly fetch the collection? If the answer is yes, then use it. Don't use it just as a workaround for the lazy loading problem.

aligh1979
Posts: 121
Posted 23:29 Oct 29, 2011 |

I am going to try removing it and to see if it works . sorry professor but I am not sure what exactly Eager Fetching does . I realized that one or two classes in csns2 are using it , that was the reason I tried it and it worked .

aligh1979
Posts: 121
Posted 23:45 Oct 29, 2011 |

Thank you , it worked by changing the inheritance . and by removing that Eager fetch I am not getting that criteria size problem either.

Thanks

cysun
Posts: 2935
Posted 23:50 Oct 29, 2011 |
aligh1979 wrote:

I am going to try removing it and to see if it works . sorry professor but I am not sure what exactly Eager Fetching does . I realized that one or two classes in csns2 are using it , that was the reason I tried it and it worked .

Eager loading means that whenever an object (e.g. Criterion) is loaded, the object it references (e.g. List<String> descriptions) is also loaded. Lazy loading means that the referenced object is only loaded when it is accessed, e.g. descriptions are only loaded when you call criterion.getDescriptions(). Lazy loading is a great feature of ORM because you don't waste resources loading data that is not used, so you should stick with lazy loading in general. You would want to use eager loading in two situations:

a) Performance optimization

Lazy loading involves two queries to the database while eager loading is only one query (with join). If the two objects are always used together (like a criterion and its descriptions), you should do eager loading to save one query.

b) Lazy loading requires a connection to the database (and in fact, requires the same entity manager / Hibernate session), so in an environment where the application can be disconnected from the database, you have to do eager loading.

aligh1979
Posts: 121
Posted 00:06 Oct 30, 2011 |

then it seems a good design to have The Eager fetching for a Criteria and its description . but one problem that occurs as I mentioned was that because the description are loaded whenever a Criteria object is loaded , it was linking each criteria to its Criteia_description collection table and was returning multiplied size  list of Criteria for a Rubric object

cysun
Posts: 2935
Posted 11:25 Oct 30, 2011 |
aligh1979 wrote:

then it seems a good design to have The Eager fetching for a Criteria and its description . but one problem that occurs as I mentioned was that because the description are loaded whenever a Criteria object is loaded , it was linking each criteria to its Criteia_description collection table and was returning multiplied size  list of Criteria for a Rubric object

Like I said, that shouldn't happen. There must be something wrong in your code.

aligh1979
Posts: 121
Posted 13:14 Nov 08, 2011 |

I have added this in my Rubric model

    @OneToMany(mappedBy = "rubric" , cascade=CascadeType.ALL )
    @OrderColumn(name = "criteria_order")
    private List<Criteria>  criterias;

the column is added to my criteria table but unfortunately is getting filled up automatically. (empty cells)

cysun
Posts: 2935
Posted 21:24 Nov 08, 2011 |
aligh1979 wrote:

I have added this in my Rubric model

    @OneToMany(mappedBy = "rubric" , cascade=CascadeType.ALL )
    @OrderColumn(name = "criteria_order")
    private List<Criteria>  criterias;

the column is added to my criteria table but unfortunately is getting filled up automatically. (empty cells)

It's supposed to be filled up automatically by Hibernate using the index of the List. Note that if you pre-create a rubric with some criteria in csns-test-insert.sql, you need to modify the INSERT statements to include the values for the criteria_order column.

aligh1979
Posts: 121
Posted 23:10 Nov 08, 2011 |

I have done that already . the problem is that it does not fill that column with the List index . I tried a lot . either the syntax should be different or there should be some other annotation around it.

cysun
Posts: 2935
Posted 23:34 Nov 08, 2011 |

It may have something to do with the way you save a Criterion. Assuming your classes look like these:

class Rubric {

    List<Criterion> criteria;

}

class Criterion {

    Rubric rubric;

}

A bidirectional association with a List is somewhat tricky because it's not exactly bidirectional - notice that the List index is kept on the Rubric side but not the Criterion side, so if you use a criterionDao.saveCriterion() to save a new criterion, the order column will be empty. It should work if you add the new criterion to the rubric, then do a rubricDao.saveRubric().