I have a one-to-Many Set defined in my mapping file, and when I use the order-by property the data in the Set will be missing rows depending on what property I use to order.
<hibernate-mapping>
<class name="domain.StudentUser" table="student_user" >
....
<set name="studentCourseses" inverse="true" order-by="import_date ASC">
<key>
<column name="student_userid" length="15" not-null="true" />
</key>
<one-to-many class="domain.StudentCourses" />
</set>
</hibernate-mapping>
public StudentUser findById(java.lang.String id) {
log.debug("getting StudentUser instance with id: " + id);
try {
StudentUser instance = (StudentUser) getSession().get(
"domain.StudentUser", id);
return instance;
} catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
Here i use import_date, but this table has about 15 properties and certain properties will cause rows to be missing from the Set while others don't. It doesn't seem to be data-type specific as I have the issue with a String property but then another String property will work fine and all data will be there. It is always the same rows that are missing no matter the sorting property used, so its not random rows.
The majority of the student_user have data missing, but not all. The rows that end up missing have nothing abnormal about them, meaning no NULL's or anything like that.
As of this point, i just removed the order-by attribute so I can get my app working property, but I still need to know why these issues are happening. So far I have not noticed this behavior in any of the other Set's that i use the order-by attribute with, just this one.
I am using Hibernate 3.5.3 and in case it's helpful, here is the mapping file for the StudentCourses table
<hibernate-mapping>
<class name="domain.StudentCourses" table="student_courses" >
<id name="id" type="integer">
<column name="id" />
<generator class="native" />
</id>
<many-to-one name="classLevel" class="domain.ClassLevel" fetch="select">
<column name="class_level_code" length="2" not-null="true" />
</many-to-one>
<many-to-one name="academicTerm" class="domain.AcademicTerm" fetch="select">
<column name="academic_term_id" not-null="true" />
</many-to-one>
<many-to-one name="studentUser" class="domain.StudentUser" fetch="select">
<column name="student_userid" length="15" not-null="true" />
</many-to-one>
<property name="academicYear" type="integer">
<column name="academic_year" not-null="true" />
</property>
<property name="term" type="string">
<column name="term" length="8" not-null="true" />
</property>
<property name="title" type="string">
<column name="title" length="64" not-null="true" />
</property>
<property name="prefix" type="string">
<column name="prefix" length="8" not-null="true" />
</property>
<property name="courseNum" type="string">
<column name="course_num" length="8" not-null="true" />
</property>
<property name="suffix" type="string">
<column name="suffix" length="8" />
</property>
<property name="sectionNum" type="string">
<column name="section_num" length="8" />
</property>
<property name="units" type="double">
<column name="units" precision="4" not-null="true" unique="true" />
</property>
<property name="letterGrade" type="string">
<column name="letter_grade" length="6" not-null="true" />
</property>
<property name="qtrGpa" type="double">
<column name="qtr_gpa" precision="4" scale="3" not-null="true" />
</property>
<property name="cumGpa" type="double">
<column name="cum_gpa" precision="4" scale="3" not-null="true" />
</property>
<property name="importDate" type="timestamp">
<column name="import_date" length="19" />
</property>
<property name="sourceFileName" type="string">
<column name="source_file_name" length="128" />
</property>
<property name="timeStamp" type="timestamp">
<column name="time_stamp" length="19" not-null="true">
<comment>on update CURRENT_TIMESTAMP</comment>
</column>
</property>
</class>
Update (More Info):
If i directly query the StudentCourses table (CORRECT) vs getting the StudentCourses data from the StudentUser mapping set (INCORRECT) gives me different results, they should match
for(StudentCourses course : getStudentService().retrieveStudentByID("861043440").getStudentCourseses()) { //MISSING DATA
System.out.println(course +" - "+course.getTerm());
}
for(StudentCourses course : (List<StudentCourses>)getStudentService().getStudentCoursesDAO().findByProperty("studentUser.studentUserid", "861043440")) { //ALL DATA CORRECT
System.out.println(course +" - "+course.getTerm());
}
Turns out it had nothing to do with sorting, as adjusting the sorting only fixed the issue for some but not all. The problem was that I had overriden the hashCode method of the StudentCourses object and it was causing collisions when the Set was being populated from the StudentUser object. I fixed this and everything is good now.
Related
When hibernate tries to paginate an entity generated using the following hbm.xml, it throws up column ambiguously defined.
<class lazy="false" dynamic-update="true" optimistic-lock="all" table="A" name="org.package.Entity">
<cache usage="read-write"/>
<id unsaved-value="null" type="java.lang.Long" name="aId">
<column name="ID_A" not-null="true" sql-type="java.lang.Long"/>
<generator class="org.package.Entity"/>
</id>
<property type="java.lang.Long" name="aGroupId" not-null="true">
<column name="ID_GROUP" not-null="true" sql-type="java.lang.Long"/>
</property>
<property type="java.lang.String" name="statusCode" not-null="true">
<column name="CD_STATUS" not-null="true" sql-type="char(30)" length="30"/>
</property>
<property type="java.lang.Long" name="templateId" not-null="false">
<column name="ID_TEMPLATE" not-null="false" sql-type="java.lang.Long"/>
</property>
<many-to-one name="aGroup" cascade="none" column="Id_Group"
class="org.package.Entity"
insert="false" update="false"/>
<many-to-one name="template" cascade="none" column="ID_TEMPLATE"
class="org.package.Entity"
insert="false" update="false"/>
</class>
What is wrong with this entity definition?
Edit: Turning it into QandA format.
ID_TEMPLATE is being condensed into one column in the query, ID_GROUP isn't.
Hibernate uses a direct string comparison to see if two properties depend on the same column. This is case sensitive, so ID_GROUP was being selected a second time as Id_Group.
Changing the cases to match, it worked.
<class lazy="false" dynamic-update="true" optimistic-lock="all" table="A" name="org.package.Entity">
<cache usage="read-write"/>
<id unsaved-value="null" type="java.lang.Long" name="aId">
<column name="ID_A" not-null="true" sql-type="java.lang.Long"/>
<generator class="org.package.Entity"/>
</id>
<property type="java.lang.Long" name="aGroupId" not-null="true">
<column name="ID_GROUP" not-null="true" sql-type="java.lang.Long"/>
</property>
<property type="java.lang.String" name="statusCode" not-null="true">
<column name="CD_STATUS" not-null="true" sql-type="char(30)" length="30"/>
</property>
<property type="java.lang.Long" name="templateId" not-null="false">
<column name="ID_TEMPLATE" not-null="false" sql-type="java.lang.Long"/>
</property>
<many-to-one name="aGroup" cascade="none" column="ID_GROUP"
class="org.package.Entity"
insert="false" update="false"/>
<many-to-one name="template" cascade="none" column="ID_TEMPLATE"
class="org.package.Entity"
insert="false" update="false"/>
</class>
Maintaining old code is fun. Hope this helps someone.
I have two tables stock and category having many-to-many relationship each other.
Stock.hbm.xml
<hibernate-mapping>
<class name="hibernate.mapping.manytomany.Stock" table="stock">
<id name="stockId" type="java.lang.Integer">
<column name="STOCK_ID" />
<generator class="identity" />
</id>
<property name="stockCode" type="string">
<column name="STOCK_CODE" length="10" not-null="true" unique="true" />
</property>
<property name="stockName" type="string">
<column name="STOCK_NAME" length="20" not-null="true" unique="true" />
</property>
<set name="categories" table="stock_category"
inverse="false" lazy="true" fetch="select" cascade="all" >
<key>
<column name="STOCK_ID" not-null="true" />
</key>
<many-to-many entity-name="hibernate.mapping.manytomany.Category">
<column name="CATEGORY_ID" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Category.hbm.xml
<hibernate-mapping>
<class name="hibernate.mapping.manytomany.Category" table="category">
<id name="categoryId" type="java.lang.Integer">
<column name="CATEGORY_ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="NAME" length="10" not-null="true" />
</property>
<property name="desc" type="string">
<column name="[DESC]" not-null="true" />
</property>
<set name="stocks" table="stock_category" inverse="true" lazy="true"
fetch="select">
<key>
<column name="CATEGORY_ID" not-null="true" />
</key>
<many-to-many entity-name="hibernate.mapping.manytomany.Stock">
<column name="STOCK_ID" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
And this is my criteria query,
Criteria c = session.createCriteria(Category.class, "c");
c.createAlias("c.stocks", "s");
c.add(Restrictions.eq("c.categoryId", 1));
c.setProjection(Projections.projectionList()
.add(Projections.property("s.stockId"))
.add(Projections.property("s.stockName")));
I need equivalent HQL for this scenario..I've tried this but it gives different result,
String query = "select c.stocks.stockId, c.stocks.stockName from Category c where
c.categoryId=1"
Let me know if you need more details.
OK, so apparently, you missed the section about joins in the documentation:
select s.stockId, // equivalent to the s.stockId projection
s.stockName // equivalent to the s.stockName projection
from Category c // equivalent to the root criteria creation
join c.stocks s // equivalent to the alias creation
where c.categoryId = 1 // equivalent to the restriction addition
I am planning to investigate this issue thoroughly. What i doubt from previous answer for now is there should be ON Clause in join statement. Pardon me if my expectation is wrong.
select s.stockId,s.stockName from Category c join c.stocks s
on c.stockId=s.stockId where c.categoryId = 1 ;
//it might be on c.CATEGORY_ID=s.CATEGORY_ID also
I am trying to map two tables using hibernate one-to-many mapping. But, always it is mapping with the wrong column. Please any body help me on this.
Level4_Master [level_id (PK/Auto Increament), company_id, level_name, next_level_id, ts]
Level3_Master [level_id (PK/Auto Increament), prv_level_id, level_name, next_level_id, ts]
Above are the two tables I am using for the mapping. Here, I wanted to map column next_level_id of Level4_Master with column prv_level_id of Level3_Master. But, hibernate always mapping the column prv_level_id with level_id of Level4_Master as FK. My mapping files are:
<hibernate-mapping>
<class name="com.pojo.Level4" table="Level4_Master">
<id name="levelId" type="java.lang.Integer">
<column name="level_id" />
<generator class="increment" />
</id>
<property name="companyId" >
<column name="company_id" length="10" not-null="true" unique="true" />
</property>
<property name="levelName">
<column name="level_name" length="20" not-null="true" unique="true" />
</property>
<property name="nextLevelId" type="java.lang.Integer">
<column name="next_level_id" />
</property>
<set name="levelList" table="Level3_Master" inverse="true" lazy="true" fetch="select">
<key>
<column name="prv_level_id" not-null="true" />
</key>
<one-to-many class="com.pojo.Level3" />
</set>
</class>
</hibernate-mapping>
and
<hibernate-mapping>
<class name="com.pojo.Level3" table="Level3_Master">
<id name="levelId" type="java.lang.Integer">
<column name="level_id" />
<generator class="increment" />
</id>
<property name="prvLevelId" >
<column name="prv_level_id" length="10" not-null="true" unique="true" />
</property>
<property name="levelName">
<column name="level_name" length="20" not-null="true" unique="true" />
</property>
<property name="nextLevelId" type="java.lang.Integer">
<column name="next_level_id" />
</property>
<set name="levelList" table="Level2_Master" inverse="true" lazy="true" fetch="select">
<key>
<column name="prv_level_id" not-null="true" />
</key>
<one-to-many class="com.pojo.Level2" />
</set>
</class>
</hibernate-mapping>
and my pojo classes are like
class Level4{
private int levelId;
private int companyId;
private String levelName;
private int nextLevelId;
private Set<Level3> levelList = new HashSet<Level3>(0);
private Timestamp ts;
//getter n setter
}
class Level3{
private int levelId;
private int prvLevelId;
private String levelName;
private int nextLevelId;
private Set<Level2> levelList = new HashSet<Level2>(0);
private Timestamp ts;
//getter n setter
}
You need to use property-ref attribute with the property name. The property must add unique="true" in the property mapping.
Example -
<hibernate-mapping><class name="com.pojo.Level4" table="Level4_Master">
<id name="levelId" type="java.lang.Integer">
<column name="level_id" />
<generator class="increment" />
</id>
<property name="companyId" >
<column name="company_id" length="10" not-null="true" unique="true" />
</property>
<property name="levelName">
<column name="level_name" length="20" not-null="true" unique="true" />
</property>
<property name="nextLevelId" type="java.lang.Integer" unique="true">
<column name="next_level_id" />
</property>
<set name="levelList" table="Level3_Master" inverse="true" lazy="true" fetch="select">
<key>
<column name="prv_level_id" not-null="true" property-ref="nextLevelId"/>
</key>
<one-to-many class="com.pojo.Level3" />
</set>
I am trying to update a field in the database to null for an integer field. I am trying to do that using hibernate. I can set object field like String and any other object to null but no integer.
<?xml version="1.0" encoding="UTF-8"?>
<class name="App_Users" table="app_users" schema="bidtool">
<id name="userId" type="int" column="user_id">
<generator class="assigned"/>
</id>
<property name="username" type="string">
<column name="username" length="20" not-null="true" />
</property>
<property name="password" type="string">
<column name="password" length="20" not-null="true" />
</property>
<property name="firstname" type="string">
<column name="firstname" length="20" />
</property>
<property name="lastname" type="string">
<column name="lastname" length="20" />
</property>
<property name="userType" type="int">
<column name="user_type" />
</property>
<many-to-one class="MasterOrg" fetch="select" name="masterOrg">
<column name="master_org_id" />
</many-to-one>
<many-to-one class="CarrierScac" fetch="select" name="carrierScac">
<column name="scac" />
</many-to-one>
<one-to-one class="AppUserDetails" fetch="select" name="details" constrained="true"/>
<set name="profiles" inverse="true">
<key>
<column name="user_id" />
</key>
<one-to-many class="Profiles" />
</set>
<set name="boilerPlates" inverse="true">
<key>
<column name="user_id" />
</key>
<one-to-many class="BoilerPlate" />
</set>
<set name="rates" inverse="true" >
<key>
<column name="user_id" />
</key>
<one-to-many class="BidToolRates" />
</set>
</class>
In the above hibernate mapping code, I want to set MasterOrg field as null.
It is best to use the object wrappers for the primitive types i.e. Integer for int, Double for double, ... etc because primitive types don't allow for the possibility of null which is always possible in a database design.
Even if a value is declared not null in the database an Object type is still useful. Consider the follow scenario as an example.
#Entity
public class ExampleEntity {
#Column(name="some_column") // assume this column is defined not null in the database
private int someProperty;
getttes settters other fields go here
}
Assume you write the following code
ExampleEntity t = new ExampleEntity();
entityManager.persist(t);
In this example t.someProperty has a value of 0 because that is the default value for an int therefore entityManager.persist works but maybe 0 is not a valid value for that column. If you have database constraints on that column then you get an error otherwise you have bad data in the database.
If someProperty was declared with wrapper type of Integer and the developer forgets to set the somePorpety value then you will get a not null exception.
A second reason to always use wrappers is simplicity as a developer I want consistent structure across entities because code is read more often that it is written so universally using wrapper types on entities makes things predictable for some one maintaining the code 5 years from now.
I have two tables as below.
"User Acc" is user's profile details and user's login details(username password) are in a seperate table called login.When I generated the entities in Netbeans IDE, there were 2 tables for login(database) table. One generated entity is "Login", another one is "LoginId".Login entity has a reference to LoginId and UserAcc entity. LoginId entity has username and password which were in login database table.UserAcc has primary key which is INT for each user.That key is the foreign key of login table.
Now I want to check the user # loging. How I do is, I create a LoginId instance and set the user name and password and then check any object which has same LoginId. Here is the code.
uName and pw are strings and taken from user input.
LoginId id=new LoginId(uName, pw);
Session ses = NewHibernateUtil.getSessionFactory().openSession();
Criteria crit = ses.createCriteria(Login.class);
crit.add(Restrictions.eq("id", id));
Entities.Login log = (Entities.Login)crit.uniqueResult();
But eventhough there are existing usernames and passwords matching with given username and password, the log is always null.
Any one tell me where I should check and what the problem is. Thank you.
And my other problem is why a separate entity("LoginId") is created for two columns(primary keys) in one database table and another entity for that its database table .
for login;
<hibernate-mapping>
<class name="Entities.Login" table="login" catalog="pcw">
<composite-id name="id" class="Entities.LoginId">
<key-property name="uname" type="string">
<column name="uname" length="10" />
</key-property>
<key-property name="pw" type="string">
<column name="pw" length="10" />
</key-property>
</composite-id>
<many-to-one name="useracc" class="Entities.Useracc" fetch="select">
<column name="UserAcc_uid" not-null="true" />
</many-to-one>
</class>
for UserAcc:
<hibernate-mapping>
<class name="Entities.Useracc" table="useracc" catalog="pcw">
<id name="uid" type="java.lang.Integer">
<column name="uid" />
<generator class="identity" />
</id>
<property name="fname" type="string">
<column name="fname" length="45" />
</property>
<property name="sname" type="string">
<column name="sname" length="45" />
</property>
<property name="RDate" type="date">
<column name="r_date" length="10" />
</property>
<property name="street" type="string">
<column name="street" length="45" />
</property>
<property name="city" type="string">
<column name="city" length="45" />
</property>
<property name="email" type="string">
<column name="email" length="45" />
</property>
<property name="tel" type="string">
<column name="tel" length="45" />
</property>
<set name="comments" inverse="true" cascade="all">
<key>
<column name="UserAcc_uid" not-null="true" />
</key>
<one-to-many class="Entities.Comment" />
</set>
<set name="logins" inverse="true" cascade="all">
<key>
<column name="UserAcc_uid" not-null="true" />
</key>
<one-to-many class="Entities.Login" />
</set>
</class>
Anyway you can use HQL to solve it it will look more and less like this:
public boolean authenticate(Sting username,String pass){
Session ses = NewHibernateUtil.getSessionFactory().openSession();
String sql = "from Login login where login.username:= username and login.pass = :=pass";
Query query = session.createQuery(sql);
query.setString("username",username);
query.setString("pass",pass);
List<Login> result = query.list();
//close session, transaction,etc....
if (result ==null)
return false;
else
return true;
}