I am having an issue in setting up a many to many relationship in my entities. And I don't understand why
failed; nested exception is org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: cardgame.bean.User.card in cardgame.bean.Card.users
My Entities:
#MappedSuperclass
#Data
public class BaseEntity implements Serializable {
#Id
#Column(name = "id", nullable = false, unique = true)
private String id;
public BaseEntity() {
this.id = UUID.randomUUID().toString();
}
}
My user emtity:
#Data
#Entity
#Table(name = "users")
public class User extends BaseEntity {
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "uuid", nullable = false)
private String uuid;
#Column(name = "email", nullable = false, unique = true)
private String email;
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Card> cards;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
My card entity:
#Data
#Entity
#Table(name = "cards")
public class Card extends BaseEntity {
#OneToMany(mappedBy = "card")
private List<User> users;
#Column(name = "strength", nullable = false)
private int strength;
#Column(name = "isActive", nullable = false)
private boolean isActive;
}
The users and cards tables have a many-to-many relationship via user_card table:
#Data
#Entity
#Table(name = "user_card")
public class UserCard implements Serializable {
#Id
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private User user;
#Id
#ManyToOne
#JoinColumn(name = "card_id", nullable = false)
private Card card;
#Column(name = "cardCount", nullable = false)
private int cardCount;
}
What am i doing incorrect. Please help me
Related
Just having a look at REST Data with Panache wondering if it is possible to exclude some entity fields from beeing exposed by the rest resource, as we need the generated REST resources only for read access pattern.
However, in the docs https://quarkus.io/guides/rest-data-panache I did not find a way to do it.
Looks like it is using Jackson for JSON, so #JsonIgnore should work for you.
#JSonIgnore can be used at the field level, or you can add it on the Getter or Setter if you want only specific parts to be ignored.
#Entity
#Table(name = "order_item")
public class OrderItem extends PanacheEntityBase {
#Id
#GenericGenerator(name = "uuid", strategy = "org.hibernate.id.UUIDGenerator")
#GeneratedValue(generator = "uuid")
#Column(name = "id", length = 36, nullable = false)
#Getter
#Setter
private String id;
#Getter
#Setter
#ManyToOne(targetEntity = Order.class)
#JsonIgnore
#JoinColumn(name = "order_id")
private Order orderId;
#Getter
#Setter
#JsonIgnore
#ManyToOne(targetEntity = Item.class)
#JoinColumn(name = "item_id")
private Item itemId;
#Getter
#Setter
#Column(name = "quantity", nullable = false)
private Integer quantity;
#Getter
#Setter
#Column(name = "price_total", nullable = false)
private Double priceTotal;
#Getter
#Setter
#Column(name = "note", columnDefinition = "text")
private String note;
}
Or you can use #JsonIgnoreProperties at the top level of the class:
#Entity
#JsonIgnoreProperties(value = { "creator", "created" }, allowSetters = false, allowGetters = true)
public class UpdateUserDeviceTokenRequest extends PanacheEntity {
#NotNull
#NotEmpty
#NotBlank
public String userDeviceToken;
#ManyToOne()
#JoinColumn(name = "creatorUser", insertable = true, updatable = false)
public AppUser creator;
#Column(insertable = true, updatable = false)
public LocalDateTime created;
public UpdateUserDeviceTokenRequest() {
}
#PrePersist
void onCreate() {
this.created = LocalDateTime.now();
}
public UpdateUserDeviceTokenRequest(#NotNull #NotEmpty #NotBlank String userDeviceToken) {
super();
this.userDeviceToken = userDeviceToken;
}
}
Please see https://github.com/quarkusio/quarkus/issues/10339 for possible issue that might arise
I have a bi-directional mapping between Customer, Order and LineItems. When trying to delete using deleteById method of Spring Data JPA, the entities are not getting deleted and I do not see any exception.
#Entity
#Table(name = "customers")
#NoArgsConstructor
#AllArgsConstructor
#Builder
#Data
public class Customer implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty(message = "customer name cannot be empty")
private String name;
#Column(unique = true)
#Email(message = "customer email address should be valid email address")
private String email;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JsonManagedReference
private Set<Order> orders;
private String password;
#Data
#NoArgsConstructor
#Builder
#AllArgsConstructor
#EqualsAndHashCode(exclude = {"customer", "lineItems"})
#ToString(exclude = {"customer", "lineItems"})
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Min(value = 2000, message = "Min order value should be 2000 INR")
#Max(value = 10_000, message = "Max order value can be 10000 INR")
private double price;
#PastOrPresent(message = "Order date cannot be in future")
private LocalDate date;
#ManyToOne
#JoinColumn(name="customer_id", nullable = false)
#JsonBackReference
private Customer customer;
#OneToMany(mappedBy = "order",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
orphanRemoval = true
)
private Set<LineItem> lineItems;
//scaffolding code
// set the bidirectional mapping
public void addLineItem(LineItem lineItem){
if(this.lineItems == null){
this.lineItems = new HashSet<>();
}
this.lineItems.add(lineItem);
lineItem.setOrder(this);
}
}
#Data
#NoArgsConstructor
#EqualsAndHashCode(exclude = "order")
#ToString(exclude = "order")
#Builder
#AllArgsConstructor
#Entity
#Table(name="line_items")
public class LineItem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private int qty;
private double price;
private String name;
#JsonIgnore
#ManyToOne
#JoinColumn(name="order_id", nullable = false)
private Order order;
}
this.orderRepository.deleteById(orderId);
Error:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.classpath.ordersapi.model.Customer.orders, could not initialize proxy - no Session\r\n\tat org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:612)\r\n\tat org.hibernate.collection.internal
My User entity follows:
#Entity
#Table
public class User {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
// non relevant attributes
#ManyToMany(fetch = FetchType.EAGER)
#Fetch(FetchMode.SELECT)
#JoinTable(name = "user2userProfile",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "userProfileId"))
private Set<UserProfile> userProfileSet;
// getters and setters
}
The UserProfile entity follows:
#Entity
#Table(name = "userProfile")
public class UserProfile {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid2")
#Column(name = "id", unique = true, insertable = true)
private String id;
#Column(name = "type", length = 15, unique = true, nullable = false)
private String type = UserProfileType.USER.getUserProfileType();
// constructors, getter and setter
}
The UserProfileType enum is
public enum UserProfileType {
USER("USER"),
READER("READER"),
WRITER("WRITER"),
ADMIN("ADMIN");
// constructor and getter
}
My UserJpaRepository is:
public interface UserJpaRepository extends JpaRepository<User, String> {
// non relevant code
List<User> findAllByUserProfileType(UserProfileType userProfileType);
}
The way it stands now, I get the following error message on the console:
org.springframework.data.mapping.PropertyReferenceException: No property userProfileType found for type User!
What is the correct declaration on UserJpaRepository to get a list of users that have a specific UserProfileType (i.e. a list of all users that have a UserProfile of type READER)?
I don't really understand why you need to have a many to many relationship from your user to your user profile.
So if we would correct that to a many to one relationship like:
in User:
#OneToMany(mappedBy = "user")
private Set<UserProfile> profiles;
in UserProfile:
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
you could just setup a search by String type in your UserProfileRepository:
List<UserProfile> findAllByType(String type);
If you now iterate the List you get, you can get all users with a certain UserProfileType:
List<User> users = userProfileRepository.findAllByType(UserProfileType.USER.toString()).stream().map(profile -> profile.getUser()).collect(Collectors.toList());
I have a large DB on MySql Workbench and I'm trying to map the relationship between the entities on Eclipse Mars thanks to Hibernate and the JPA module. The fact is that I receive the error:
"In attribute 'personAddresses', the "mapped by" attribute 'peopleAdd' has an invalid mapping type for this relationship."
This are the entities involved.
1
I've to say that making a forward engineering, Hibernate creating for me an AddressId class, where the composite primary key of Address is mapped. I suspect that the problem could be this, but I'm not certain, can you help me please?
Under I post the code so that it's more clear to understand how the classes are implemented.
#Entity
#IdClass(AddressId.class)
#Table(schema = "YouDroop", name = "Address")
public class Address implements Serializable
{
...
private Collection<Person> peopleAdd = new HashSet<Person>();
#Id
#Column(name = "Address", length = 45, unique = true, nullable = false)
private String address;
#Id
#Column(name = "Number", unique = true, nullable = false)
private int number;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "PersonHasAddress",
joinColumns = {
#JoinColumn(name = "Address_Address", referencedColumnName = "Address", nullable = false),
#JoinColumn(name = "Address_Number", referencedColumnName = "Number", nullable = false)
},
inverseJoinColumns = {#JoinColumn(name = "Person_Email", referencedColumnName = "Email", nullable = false)}
)
public Collection<Person> getPeopleAddressed(){
return this.peopleAdd;
}
public void setPeopleAddressed(Collection<Person> people){
this.peopleAdd = people;
}
}
public class AddressId implements Serializable
{
private String address;
private int number;
public AddressId(){}
public AddressId(String address, int number) {
super();
this.address = address;
this.number = number;
}
...
}
#Entity
#Table(name = "Person", schema = "YouDroop", uniqueConstraints =
{ #UniqueConstraint(columnNames = "NickName"),
#UniqueConstraint(columnNames = "Password") })
public class Person implements Serializable
{
...
private Collection<Address> addresses = new HashSet<Address>();
...
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "peopleAdd")
public Collection<Address> getPersonAddresses(){
return this.addresses;
}
public void setPersonAddresses(Collection<Address> addresses){
this.addresses = addresses;
}
}
Since you placed you #ManyToMany annotation on your getter method (or property) and not on the field. The mappedBy attribute should reference the property instead and not the field.
#ManyToMany
public Collection<Person> getPeopleAddressed() {
...
}
So your mappedBy attribute should have been
#ManyToMany(mappedBy="peopleAddressed")
public Collection<Address> getPersonAddresses() {
...
}
I need help with this. With code is more clear, this is my function to persist:
public String finalizarCompra() {
Pedido pedido = new Pedido();
pedido.setEstado("almacen");
pedido.setFechaVenta(new Date());
pedido.setIdUsuario(loginBean.getUsuario());
Producto p;
Integer i;
DetPedido detPedido;
List<DetPedido> lista = new ArrayList<>();
for (Map.Entry e : productos.entrySet()) {
detPedido = new DetPedido();
p = (Producto) e.getKey();
i = (Integer) e.getValue();
detPedido.setProducto(p);
detPedido.setCantidad(i);
detPedido.setPrecioUnidad(p.getPrecioUnidad());
detPedido.setPedido(pedido);
lista.add(detPedido);
detPedidoBean.insert(detPedido);
}
pedido.setDetPedidoCollection(lista);
pedidoBean.insert(pedido);
return "";
}
This is my Pedido Entity:
#Entity
public class Pedido implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "FECHA_VENTA")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaVenta;
#Column(name = "FECHA_ENVIO")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaEnvio;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 50)
#Column(name = "ESTADO")
private String estado;
#JoinColumn(name = "ID_USUARIO", referencedColumnName = "ID_USUARIO")
#ManyToOne(optional = false)
private Usuario idUsuario;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "pedido")
private Collection<DetPedido> detPedidoCollection;
// Getters and Setters //
This is my DetPedido Entity:
#Entity
public class DetPedido implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected DetPedidoPK detPedidoPK;
#Basic(optional = false)
#NotNull
#Column(name = "CANTIDAD")
private Integer cantidad;
#Basic(optional = false)
#NotNull
#Column(name = "PRECIO_UNIDAD")
private Double precioUnidad;
#JoinColumn(name = "ID_PRODUCTO", referencedColumnName = "ID_PRODUCTO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Producto producto;
#JoinColumn(name = "ID_PEDIDO", referencedColumnName = "ID_PEDIDO", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Pedido pedido;
// Getters and Setters //
And this is my DetPedidoPK:
#Embeddable
public class DetPedidoPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "ID_PEDIDO")
private Integer idPedido;
#Basic(optional = false)
#NotNull
#Column(name = "ID_PRODUCTO")
private Integer idProducto;
// Getters and Setters //
The Entities ara generated automatically from the Database, also DetPedidoPK, and now I don't know how to save a Pedido. I tried with the code above, but it doesn't work.
Can anybody help me?
Greetings.
If you are using JPA 1.0 and this entity model, then you will need to persist and flush both Producto and Pedido instances to have their IDs assigned before you can persist the DetPedido instance that will reference them. Once that is done, you will need to manually set the id values in DetPedido's DetPedidoPK instance so that they match the referenced Producto and DetPedido key values. You cannot insert DetPedido without the DetPedidoPK values having been set.
JPA 2.0 supports derived IDs, which allows marking the relationship as either #ID or #MapsId, indicating that the ID values should be pulled from the joincolumn associated to the relationship. In this case, it would become:
#ManyToOne(optional = false)
#MapsId("idProducto")
private Producto producto;
#ManyToOne(optional = false)
#MapsId("idPedido")
private Pedido pedido;
If you wanted, you could do away with the embeddable within DetPedido and just mark the relationships as the #Id, and because it is composite you would use the DetPedidoPK as the PK class.