I got issues with my hibernate query. There are two classes, Wohnung and Kosten. Each Kosten has a relation to a Wohnung.
In my controller, kosten.getWohnung() returns null. It looks as Hibernate did not select the related Wohnung.
This is the method of my KostenDao. I assume that I do have to change the query?
public Kosten findById(int id) {
return (Kosten) getSession().createQuery("from Kosten k where k.id = " + id).uniqueResult();
}
for better understanding, here is part of my Kosten model:
#Entity
#Table(name="WNG_KOSTEN")
public class Kosten {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;
// #Column(name = "INSERT_DT", nullable = false)
// #Value("${props.insertDt:SYSDATE}")
// protected java.util.Date insertDt;
#ManyToOne
#JoinColumn(name="WOHNUNG_ID")
private Wohnung wohnung;
...
Use EAGER fetch type, FetchType.LAZY is the default fetch type for all Hibernate relationships.
#ManyToOne (fetch=FetchType.EAGER)
#JoinColumn(name="WOHNUNG_ID")
private Wohnung wohnung;
Related
I am trying to use Hibernate Criteria api to fetch only the topics based on the USER_ID but have no idea how to do it using the criteria.
My Tables are "topic_users" (below)
and "topics" table (below)
I know how to do it using SQL, this would be something like:
SELECT TOPICNAME
FROM topic_users INNER JOIN topics on topic_users.TOPICS_TOPICS_ID = topics.TOPICS_ID
WHERE topic_users.USER_ID = 1
This will return all TOPICNAME of USER_ID 1 which is exactly what I want but how I can do this with Hibernate Criteria. So far I have this in my Repository class (see below) but this will only return a highly nested JSON array. I could loop through the objects, use a DTO and build my response or try the Hibernate createSQLQuery method that will let me call a native SQL statement directly (haven't tried that yet)...but I am trying to learn the Criteria so I hope anyone can answer my query.
#Repository("userTopicsDao")
public class UserTopicsDaoImpl extends AbstractDao<Integer, UserTopics>implements UserTopicsDao {
#Override
public List<UserTopics> findMyTopics(int userId) {
Criteria crit = createEntityCriteria();
crit.add(Restrictions.eq("userId", userId));
List<UserTopics> userTopicsList = (List<UserTopics>)crit.list();
return userTopicsList;
}
and my TOPIC_USERS Entity where I have mapped the TOPICS
#Entity
#Table(name="TOPIC_USERS")
public class UserTopics {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="TOPICUSER_ID")
private Integer id;
#Column(name="USER_ID")
private Integer userId;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "TOPICS_ID")
private Set<Topics> topicsUser;
//getter and setters
Ok starting from the ground up.. you entity classes should look like this:
#Entity
#Table(name="TOPIC_USERS")
public class UserTopics {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="TOPICUSER_ID")
private Integer id;
#Column(name="USER_ID")
private Integer userId;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "TOPICS_TOPICS_ID")
private Topics topics;
Your Topics class should look like this:
#Entity
#Table(name="TOPICS")
public class Topic {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="TOPICUS_ID")
private Integer id;
#Column(name="TOPICNAME")
private Integer topicName;
#OneToMany(mappedBy = "topics")
private Set<UserTopics> userTopics;
Finally the Criteria:
Version 1) You get entire entity:
Criteria c = session.createCriteria(Topics.class, "topics");
c.createAlias("topics.userTopics", "userTopics");
c.add(Restrictions.eq("userTopics.userId", userId));
return c.list(); // here you return List<Topics>
Version 2) You project only the topicname:
Criteria c = session.createCriteria(Topics.class, "topics");
c.createAlias("topics.userTopics", "userTopics");
c.add(Restrictions.eq("userTopics.userId", userId));
c.setProjection(Projections.property("topics.topicName"));
List<Object[]> results = (List<Object[]>)c.list();
// Here you have to manually get the topicname from Object[] table.
}
I am using spring 4.1.4.RELEASE + hibernate 4.3.6.Final, here is my entity code:
public class BaseEntity implements Serializable {
}
public class MarketInfo extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#Column(name = "market_id", unique = true, length = 15)
private String marketId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "market")
private List<MarketChannelGroup> channelGroups;
public List<MarketChannelGroup> getChannelGroups() {
return channelGroups;
}
public void setChannelGroups(List<MarketChannelGroup> channelGroups) {
this.channelGroups = channelGroups;
}
...
}
public class MarketChannelGroup extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "market_id", referencedColumnName = "market_id")
private MarketInfo market;
...
}
From my test I can see the channelGroups in MarketInfo is working fine (if I don't call getChannelGroups(), then channelGroups is null), however if I call getChannelGroups(), the MarketInfo inside each MarketChannelGroup gets fetched, while this should not happen since market's fetch mode is FetchType.LAZY.
From console I do see the following hibernate log when I call its getter:
Hibernate: select channelgro0_.market_id as market_i5_12_1_, channelgro0_.id as id1_9_1_, channelgro0_.id as id1_9_0_, channelgro0_.channel_group_id as channel_2_9_0_, channelgro0_.channel_group_name as channel_3_9_0_, channelgro0_.channel_group_type as channel_4_9_0_, channelgro0_.market_id as market_i5_9_0_ from market_channel_group channelgro0_ where channelgro0_.market_id=?
Hibernate: select marketinfo0_.id as id1_12_0_, marketinfo0_.enable_flag as enable_f2_12_0_, marketinfo0_.enable_time as enable_t3_12_0_, marketinfo0_.market_id as market_i4_12_0_, marketinfo0_.market_name as market_n5_12_0_, marketinfo0_.stb_count as stb_coun6_12_0_ from market_info marketinfo0_ where marketinfo0_.market_id=?
Hibernate: select marketinfo0_.id as id1_12_0_, marketinfo0_.enable_flag as enable_f2_12_0_, marketinfo0_.enable_time as enable_t3_12_0_, marketinfo0_.market_id as market_i4_12_0_, marketinfo0_.market_name as market_n5_12_0_, marketinfo0_.stb_count as stb_coun6_12_0_ from market_info marketinfo0_ where marketinfo0_.market_id=?
Hibernate: select marketinfo0_.id as id1_12_0_, marketinfo0_.enable_flag as enable_f2_12_0_, marketinfo0_.enable_time as enable_t3_12_0_, marketinfo0_.market_id as market_i4_12_0_, marketinfo0_.market_name as market_n5_12_0_, marketinfo0_.stb_count as stb_coun6_12_0_ from market_info marketinfo0_ where marketinfo0_.market_id=?
could anyone help?
UPDATE
there is no optional method for ManyToOne annotation, so the solution in OneToOne doesn't work for my case.
Move the #OneToMany annotation from the declaration to the getter method, like this:
private List<MarketChannelGroup> channelGroups;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "market")
public List<MarketChannelGroup> getChannelGroups() {
return channelGroups;
}
How is your configuration archive? Look if you are using the filter OpenEntityManagerInViewFilter. If you are using it, always that you call the method Lazy getChannelGroups() the hibernate will get fetch inside each element.
You have to take oneToMany annotation to getter if #id is on the getter. Lazy works but if you or some framework get the lazy property in that transction the get method fire the select.
I have a (abbreviated) class that looks like this:
#Entity
#Table
#SecondaryTable(
name = "SUPER_ADMIN",
pkJoinColumns = #PrimaryKeyJoinColumn(
name = "PERSON_ID",
referencedColumnName = "PERSON_ID"))
public class Person {
#Id
#Column(name = "PERSON_ID")
private Long personId;
// getters/setters omitted for brevity
}
The SUPER_ADMIN table has only one column: PERSON_ID. What I would like to do is add private Boolean superAdmin to Person where it would be true if the PERSON_ID is present in that table.
Is this even possible? I am using Hibernate as my JPA provider, so I'm open to proprietary solutions as well.
UPDATE
It seems like I should have done more homework. After poking around, I see that #SecondaryTable does inner joins and not outer joins. Therefore, my idea here will not work at all. Thanks to #Elbek for the answer -- it led me to this revelation.
You can use JPA callback methods.
public class Person {
#Id
#Column(name = "PERSON_ID")
private Long personId;
#Transient
private transient Boolean superAdmin = false;
// This method will be called automatically when object is loaded
#PostLoad
void onPostLoad() {
// BTW, personId has to be present in the table since it is id column. Do you want to check if it is 1?
superAdmin = personId == 1;
}
}
or you can create easy getter method.
public class Person {
#Id
#Column(name = "PERSON_ID")
private Long personId;
boolean isSuperAdmin() {
return personId == 1;
}
}
You can't have an optional relationship with a #SecondaryTable. You do not have any other choice than using a #OneToOne optional relationship in that case.
I' using Hibernate 3.6.1 to map three entities
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class Entry {
private Long id;
private Date publishedAt;
#Id
public getId() {...}
...
}
#Entity
public class Category {
private Long id;
List<Podcast> podcasts;
#Id
public getId() {...}
#OneToMany(mappedBy = "category", cascade = {CascadeType.ALL}, fetch = FetchType.EAGER)
#OrderBy("publishedAt")
public List<Podcast> getPodcasts() {
return podcasts;
}
}
and
#Entity
public class Podcast extends Entry {
private Category category;
#ManyToOne(fetch = FetchType.EAGER)
public PodcastsCategory getCategory() {
return category;
}
}
If i try to fetch a Category instance, i get an Exception
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'podcasts0_.Entry.publishedAt' in 'order clause'
What causes this exception? Whats wrong with this mapping?
It's caused by the following bug: HHH-3577 Wrong SQL in order by clause when using joined subclasses.
As a workaround you can remove #OrderBy and fetch = FetchType.EAGER on podcasts and load category using the following query instead of get():
SELECT DISTINCT c
FROM Category c LEFT JOIN FETCH c.podcasts p
WHERE c.id = ?
ORDER BY p.publishedAt
You could try the annotation #MappedSuperClass. See section 2.2.4.4. Inherit properties from superclasses of the hibernate documentation.
Can anyone tell me whether Hibernate supports associations as the pkey of an entity? I thought that this would be supported but I am having a lot of trouble getting any kind of mapping that represents this to work. In particular, with the straight mapping below:
#Entity
public class EntityBar
{
#Id
#OneToOne(optional = false, mappedBy = "bar")
EntityFoo foo
// other stuff
}
I get an org.hibernate.MappingException: "Could not determine type for: EntityFoo, at table: ENTITY_BAR, for columns: [org.hibernate.mapping.Column(foo)]"
Diving into the code it seems the ID is always considered a Value type; i.e. "anything that is persisted by value, instead of by reference. It is essentially a Hibernate Type, together with zero or more columns." I could make my EntityFoo a value type by declaring it serializable, but I wouldn't expect this would lead to the right outcome either.
I would have thought that Hibernate would consider the type of the column to be integer (or whatever the actual type of the parent's ID is), just like it would with a normal one-to-one link, but this doesn't appear to kick in when I also declare it an ID. Am I going beyond what is possible by trying to combine #OneToOne with #Id? And if so, how could one model this relationship sensibly?
If the goal is to have a shared primary key, what about this (inspired by the sample of Java Persistence With Hibernate and tested on a pet database):
#Entity
public class User {
#Id
#GeneratedValue
private Long id;
#OneToOne(cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Address shippingAddress;
//...
}
This is the "parent" class that get inserted first and gets a generated id. The Address looks like this:
#Entity
public class Address implements Serializable {
#Id #GeneratedValue(generator = "myForeignGenerator")
#org.hibernate.annotations.GenericGenerator(
name = "myForeignGenerator",
strategy = "foreign",
parameters = #Parameter(name = "property", value = "user")
)
#Column(name = "ADDRESS_ID")
private Long id;
#OneToOne(mappedBy="shippingAddress")
#PrimaryKeyJoinColumn
User user;
//...
}
With the above entities, the following seems to behave as expected:
User newUser = new User();
Address shippingAddress = new Address();
newUser.setShippingAddress(shippingAddress);
shippingAddress.setUser(newUser); // Bidirectional
session.save(newUser);
When an Address is saved, the primary key value that gets inserted is the same as the primary key value of the User instance referenced by the user property.
Loading a User or an Address also just works.
Let me know if I missed something.
PS: To strictly answer the question, according to Primary Keys through OneToOne Relationships:
JPA 1.0 does not allow #Id on a OneToOne or ManyToOne, but JPA 2.0 does.
But, the JPA 1.0 compliant version of Hibernate
allows the #Id annotation to be used on a OneToOne or ManyToOne mapping*.
I couldn't get this to work with Hibernate EM 3.4 though (it worked with Hibernate EM 3.5.1, i.e. the JPA 2.0 implementation). Maybe I did something wrong.
Anyway, using a shared primary key seems to provide a valid solution.
Yes that is possible.
Look at the following example using Driver and DriverId class as id for Driver.
#Entity
public class Drivers {
private DriversId id; //The ID which is located in another class
public Drivers() {
}
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "personId", column = #Column(name = "person_id", nullable = false))})
#NotNull
public DriversId getId() {
return this.id;
}
//rest of class
}
Here we are using personId as the id for Driver
And the DriversId class:
//composite-id class must implement Serializable
#Embeddable
public class DriversId implements java.io.Serializable {
private static final long serialVersionUID = 462977040679573718L;
private int personId;
public DriversId() {
}
public DriversId(int personId) {
this.personId = personId;
}
#Column(name = "person_id", nullable = false)
public int getPersonId() {
return this.personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof DriversId))
return false;
DriversId castOther = (DriversId) other;
return (this.getPersonId() == castOther.getPersonId());
}
public int hashCode() {
int result = 17;
result = 37 * result + this.getPersonId();
return result;
}
}
You can do this by sharing a primary key between EntityFoo and EntityBar:
#Entity
public class EntityBar
{
#Id #OneToOne
#JoinColumn(name = "foo_id")
EntityFoo foo;
// other stuff
}
#Entity
public class EntityFoo
{
#Id #GeneratedValue
Integer id;
// other stuff
}
You have to use #EmbeddedId instead of #Id here.
And EntityFoo should be Embeddable.
Another way is to put an integer, and a OneToOne with updateble and instertable set to false.