i have an Entity with following mappings:
#Entity
#Table(name = "template_product")
public class TemplateProductBean implements Serializable {
private static final long serialVersionUID = -1821696115330320798L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column(name = "product_id")
private Long productId;
// bi-directional many-to-one association to
// Template
#ManyToOne
#JoinColumn(name = "template_id")
private TemplateBean template;
The Template Bean looks as following:
#Entity
#Table(name = "template")
public class TemplateBean implements Serializable {
private static final long serialVersionUID = 3752018564161042623L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "platform_id")
private Long platformId;
#Column(name = "template_name")
private String templateName;
// bi-directional many-to-one association to
// TemplateProduct
#OneToMany(mappedBy = "template")
private List<TemplateProductBean > templateProductBean;
The Problem im facing is, im very untrained when it comes down to use the JPA Interfaces. How can i use these to get the following query:
select template
from Template template
join TemplateProductBean templateProducts
on template.templateId = templateProducts.template.templateId
where templateProducts.productId in :templateProductIdList
How can i use the JPA Interfaces( javax.persistence.criteria.Root, javax.persistence.Join etc.) to build this query as a Predicate? I'm sorry if im being unclear, i have to use this and im not used to using the JPA. Thanks
I think this should work
select t from TemplateBean t inner join t.templateProductBean tpb where tpb.productId in :templateProductIdList
More details on inner joins and HQL in general: documentation
Related
I am building a REST API with Spring 2.1 and I am getting duplicate data to consult the ManyToOne relationship.
Localidad:
#Entity
#Table(name = "localidad")
public class Localidad implements Serializable {
private static final long serialVersionUID = -7258462202419598287L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idLocalidad;
private String nombreLocalidad;
private BigDecimal precioEnvio;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "provinciaIdProvincia")
private Provincia provincia;
public Localidad() {}
public Localidad(String nombreLocalidad, BigDecimal precioEnvio) {
this.nombreLocalidad = nombreLocalidad;
this.precioEnvio = precioEnvio;
}
...
Provincia:
#Entity
#Table(name = "provincia")
public class Provincia implements Serializable {
private static final long serialVersionUID = 3324427184301992595L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idProvincia;
private String nombreProvincia;
#OneToMany(mappedBy= "provincia", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<Localidad> localidades = new HashSet<Localidad>();
public Provincia() {}
public Provincia(String nombreProvincia) {
this.nombreProvincia = nombreProvincia;
}
...
I access information by implementing CrudRepository and Service #Autowired
Duplicate data HTTP GET Request:
Duplicate Data
Thanks
The problem is caused by Jackson doing cyclic serialization on the provincia and the localidades fields. This can be solved by using the #JsonIgnoreProperties annotation. so in the Localidad class or entity add the annotation as follows:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "provinciaIdProvincia")
#JsonIgnoreProperties("localidades")
private Provincia provincia;
And in the Provincia class modifiy the Set<Localidad>(btw you can just use a List<Localidad> instead) like this:
#OneToMany(mappedBy= "provincia", cascade = CascadeType.ALL, fetch =
FetchType.LAZY)
#JsonIgnoreProperties("provincia")
private Set<Localidad> localidades = new HashSet<Localidad>();
With this changes your Rest API should now show no duplicates. You have to ignore the fields that define the association between the two classes or entities. In case you have used #JsonProperty to define the fields names, use the names used in the #JsonProperty definition for #JsonIgnoreProperties.
I am looking to create a DAO which represents a join of two tables with Java Hibernate. Here is the SQL I'd like to represent (Postgres 9.6 incase that matters):
SELECT tableOneValue, tableTwoValue
FROM table_one, table_two
WHERE table_one_filter = 2 AND table_one_id = table_two_id;
These tables have a OneToOne relationship.
Table1.java
#Entity
#Data
#Table(name="table_one")
public class TableOneDao implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_one_id")
private int tableOneId;
#Column(name = "table_one_value")
private String tableOneValue;
#Column(name = "table_one_filter")
private int tableOneFilter;
}
Table2.java
#Entity
#Data
#Table(name="table_two")
public class TableTwoDao implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "table_twp_id")
private int tableTwpId;
#Column(name = "table_two_value")
private String tableTwoValue;
}
I'm very new to hibernate so maybe this isn't the right way to think with it. What I would love to do is define a SomeDao class where I can do: daoManager.findAll(SomeDao.class, Pair.of("tableOneFilter", 2));
This would return a List<SomeDao> where we get all the rows that satisfy tableOneFilter == 2.
You need to use the #OneToOne and #JoinColumn annotation.
Pay special attention to the userDetail attribute mapping.
For example, the user class:
#Entity
#Table(name = "USERS")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_ID")
private long id;
#Column(name = "USERNAME", nullable = false, unique = true)
private String username;
#Column(name = "PASSWORD")
private String password;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name="USR_DET_ID")
private UserDetail userDetail;
// Add Constructor, Setter and Getter methods
}
And this user details class:
#Entity
#Table(name = "USER_DETAILS")
public class UserDetail {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USR_DET_ID")
private long id;
#Column(name = "FIRST_NAME")
private String firstName;
#Column(name = "LAST_NAME")
private String lastName;
#Column(name = "EMAIL")
private String email;
#Column(name = "DBO")
private LocalDate dob;
// Add Constructor, Setter and Getter methods
}
Check the full code here.
Here is a JPA query which will work with your existing entity structure with the latest version of hibernate.
SELECT t1.tableOneValue, t2.tableTwoValue
FROM TableOneDao AS t1 JOIN TableTwoDao AS t2 ON t1.table_one_id = t2.table_two_id
WHERE t1.table_one_filter = ?
You can write a JPQL statement which is much better. Here is the sample solution:
SELECT NEW com.test.package.dao(t1.valueOne, t2.valueTwo)
FROM table_one t1 JOIN table_two t2
WHERE t1.filter = 2 AND t1.id = t2.id;
Please refer to this link and jump to the section where it mentions Result Classes (Constructor Expressions). Hope it helps. Thanks.
I'm trying to build a multi-language database, so I've used this database design as a approach for mine.
Now I've two problems/questions:
I want to retrieve all LocalizedEvent for a given language and given categoryId. How can I make a inner join over the LocalizedCategory table with Hibernate Criteria API?
With SQL I would make this statement to get all LocalizedEvent + LocalizedCategory:
SELECT * FROM event e
INNER JOIN
localized_event le ON (le.event_id = e.event_id)
INNER JOIN
localized_category lc ON (lc.category_id = e.category_id)
WHERE
le.locale = 'de' AND lc.locale = 'de'
My current approach looks like this without getting the LocalizedCategory (with Criteria API):
Criteria c = session.createCriteria(LocalizedEvent.class, "localizedEvent");
c.createAlias("localizedEvent.event", "event");
c.createAlias("event.category", "category");
c.add(Restrictions.eq("category.categoryId", categoryId));
c.add(Restrictions.eq("localizedEvent.locale", language));
I think my mapping is not 100% correct. The entity LocalizedEvent should have a property localizedCategory, but I don't want to save the ID of this localizedCategory (therefore I'm using the #Transient annotation) in the LocalizedEvent table, e.g. using a ManyToOne relation (joining LOC_CATEGORY_ID). But I think it's not possible to do this, isn't it? I would have to map this transient field to LocalizedEvent "manually", because Hibernate is not supporting this mapping (if I'm right).
(Using JDBC this property/mapping would cause no problems, because I can easily make my inner joins and assign the property localizedCategory to the LocalizedEvent in a RowMapper or so).
My entities looks like this:
Event
#Entity
#Table(name = "EVENT")
public class Event {
#Id
#GeneratedValue
#Column(name = "EVENT_ID", unique = true)
private Long eventId;
#Column(name = "DATE")
private Date date;
#OneToMany(mappedBy = "event")
private Set<LocalizedEvent> localizedEvents;
#ManyToOne
#JoinColumn(name = "CATEGORY_ID")
private Category category;
}
LocalizedEvent
#Entity
#Table(name = "LOCALIZED_EVENT")
public class LocalizedEvent {
#Id
#GeneratedValue
#Column(name = "LOC_EVENT_ID")
private Long locEventId;
#ManyToOne
#JoinColumn(name = "EVENT_ID")
private Event event;
#Transient
private LocalizedCategory localizedCategory;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "LOCALE")
private String locale;
}
Category
#Entity
#Table(name = "CATEGORY")
public class Category {
#Id
#GeneratedValue
#Column(name = "CATEGORY_ID", unique = true)
private Long categoryId;
#OneToMany(mappedBy = "category")
private Set<LocalizedCategory> localizedCategories;
#OneToMany(mappedBy = "category")
private Set<Event> events;
}
LocalizedCategory
#Entity
#Table(name = "LOCALIZED_CATEGORY")
public class LocalizedCategory {
#Id
#GeneratedValue
#Column(name = "LOC_CATEGORY_ID")
private Long locCategoryId;
#ManyToOne
#JoinColumn(name = "CATEGORY_ID")
private Category category;
#Column(name = "NAME")
private String name;
#Column(name = "LOCALE")
private String locale;
}
I am currently developing a java ee application but i am having problems with the JPA.
I have two entities:
#Entitiy
public class Restaurant implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Desk> desks;
}
#Entitiy
public class Desk implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name = "restaurant_id")
private Restaurant restaurant;
}
And i am storing the desks with the following code:
Desk desk = new Desk();
desk.setNumber(Integer.toString(x));
desk.setRestaurant(restaurant);
em.persist(desk);
But now the strange thing is that the list of desks in the entity restaurant is empty but the restaurant value in the entity desk is correct.
The Database shema looks like that:
RESTAURANT (ID)
DESK (ID, RESTAURANT_ID)
RESTAURANT_DESK (RESTAURANT_ID, DESK_ID)
The table RESTAURANT_DESK is always empty. Why is this third table generated? And why is the list of desks in the entity restaurant empty?
For a bi-directional mapping, you need to give mappedBy attribute in the Restaurant entity to indicate the inverse relationship:
#Entity
public class Restaurant implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="restaurant")
private List<Desk> desks;
}
I found the problem. I had to add the entity desk also to the restaurant list.
Desk desk = new Desk();
desk.setNumber(Integer.toString(x));
desk.setRestaurant(restaurant);
restaurant.getDesks().add(desk);
em.persist(desk);
I have this error
The collection-valued path 'c.medecin' cannot be resolved to a valid association field
The state field path 'm.id' cannot be resolved to a valid type.
when I execute this request
createQuery("select c from Creneaux c join c.medecin m where m.id=:idMedecin").setParameter("idMedecin", medecin.getId());
I use these 2 tables : MEDECINS(ID) and CRENEAUX(ID, ID_MEDECIN)
#Entity
#Table(name = "medecins")
#XmlRootElement
public class Medecins implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "medecin"/*"idMedecin"*/)
private transient List<Creneaux> creneauxList;
}
and
#Entity
#Table(name = "creneaux")
public class Creneaux implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID")
private Long id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ID_MEDECIN")
private transient Medecins medecin;
#Column(name = "ID_MEDECIN")
private BigInteger idMedecin;
I begin in JPA, so I a not sure about all the code. I think the Query is correct, but I don't know how to annotate the entities to make the Query valid.
Thanks
I wonder why adding the last attribute in the second Entity that is: idMedecin while you've already joined the two entities to each others. Maybe you should omit it.
If the purpose of the query is to select all the creneaux related to the given medecin, then you ought to change the query to:
createQuery("SELECT c FROM Creneaux c WHERE c.medecin.id = :idMedecin").setParameter("idMedecin", medecin.getId());
Where medecin.getId() should be provided before the query's execution.
That's because the Creneaux.medecin field is transient. Transient fields are ignored by JPA.
Another thing is that you don't have two join these two entities. If you want to filter by Medecin ID it's enough to execute a query as #Omar described.