How to declare JPARepository on the basis of a composite ID? - java

I have a class with 2 ids like this
#Entity
#IdClass(PersonID.class)
public class Person{
#Id
private int id;
#Id
private int flag;
...
}
public class PersonID{
int id;
int flag;
}
I want to use JPARepository<Person,???> to use his methods but i don't now how !!

I think this might work:
JpaRepository<Person, PersonID>

Related

Link between entities with JPA

I'm creating a java web application, and for the backend, I use JPA and a h2 database.
I have for the moment one class called Secteur and one class called Bassin.
In my conception, one Secteur can have many Bassin, but one Bassin can have just one Secteur. Moreover it's not possible to create a Bassin if there is no Secteur already created (because one Bassin is already linked to a Secteur).
This is the Secteur class :
#Entity
public class Secteur {
#Id
#GeneratedValue
private int id;
private String nom;
...
}
And this is the Bassin class :
#Entity
public class Bassin {
#Id
#GeneratedValue
private int id;
private String nomBassin;
private int tailleMax;
private int tailleUtilise;
private Date dernierNetoyage;
private String etatBassin;
private int idSecteur;
...
}
After a lot of research, I had seen that different annotation exist like #ManyToOne, #OneToMany, etc. But I don't know how to use them in order to resolve my problem.
1) Can you help me please ?
2)Moreover if I use these annotations can I remove "private int idSecteur" ?
Thank you in advance for your help !
The Secteur entity mapping should be:
#Entity
public class Secteur {
#Id
#GeneratedValue
private int id;
private String nom;
#ManyToOne
#JoinColumn(name="secteur_id", nullable=false)
private Bassin bassin;
}
The bassin entity mapping should be:
#Entity
public class Bassin {
#Id
#GeneratedValue
private int id;
private String nomBassin;
private int tailleMax;
private int tailleUtilise;
private Date dernierNetoyage;
private String etatBassin;
#OneToMany(mappedBy="bassin")
    private Set<Secteur> secteurs;
}
Note that secteur_id in the annotation refers to the name of secteur id column in database.
I advise you to take a look to this more complete reference

Generic method to retrieve data from a property of superclass

I have some entities extended with a generic BaseEntity which have a Id property and I want to do a method where I pass an entity and retrieve that id, i.e.
BaseEntity
public abstract class BaseEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
// Getters and setters
}
Entity
public class Entidad extends BaseEntity {
protected String name;
protected String image;
protected Set<ContactForm> contactForms = new HashSet<ContactForm>();
}
(ContactForm also extends from BaseEntity)
And I want do something like this:
List<Long> longlist;
longlist = retrieveIds(entidad.getContactForms);
[...]
public List<Long> retrieveIds(Set<BaseEntity> entidades){
List<Long> lista = new ArrayList<Long>();
for(BaseEntity entidad : entidades){
lista.add(entidad.getId());
}
return lista;
}
It's possible? How?
Yes. That is possible.
Just create a method in your super class and override that method in all child's which return id of that class.
Create a method getId() to return the Id of BaseEntity
BaseEntity
public abstract class BaseEntity implements Serializable{
private Long id;
public Long getId() {
return this.id;
}
}

java : advanced inheritance to jpa

I have a problem with abstract class where we implement an interface.
Now the interface is in our implementation of the abstract class other than the other implementation.
I'll show you the code here:
#MappedSuperclass
public abstract class AbstractOrder {
#Id
#GeneratedValue
private Long idOrder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="datum")
private Date date = new Date();
#OneToMany(targetEntity=IOrderLine.class)
private List<IOrderLine> orderLines = new ArrayList<IOrderLine>();
private String refOrder;
...
}
#Entity
#Table(name="supplyorders")
public class SupplyOrder extends AbstractOrder implements Comparable<SupplyOrder>, Serializable {
#ManyToOne
private Supplier supplier;
#Enumerated(EnumType.STRING)
private SupplyOrderStatus status = SupplyOrderStatus.TOBESUPPLIED;
#ElementCollection
private Set<CustomerOrder> customerOrders = new HashSet<CustomerOrder>();
...
}
#Entity
#Table(name="customerorders")
public class CustomerOrder extends AbstractOrder implements commparable<CustomerOrder>,Serializable {
#ManyToOne
private Customer customer;
#ManyToOne
private Place place;
#ManyToOne
private User vendor;
private double deposit;
#Enumerated(EnumType.STRING)
private OrderStatus status = OrderStatus.CREATED;
}
#MappedSuperclass
public interface IOrderLine {
double getSubTotal();
int getQuantity();
Furniture getFurniture();
}
#Entity
#Table(name="supplyorderlines")
public class SupplyOrderLine implements IOrderLine, Serializable {
#Id
#GeneratedValue
private Long id;
#OneToMany
private List<CustomerOrderLine> customerOrderLines = new ArrayList<CustomerOrderLine>();
...
}
and of course a class CustormerOrderLine that implements IOrderLine.
Now for the supplyOrder they have supplyOrderLines in them and the customerOrder has the CustomerOrderLine in them.
The fault we get is that the abstract class doesn't know what implementation to take of the interface IOrderLine.
How can I override the field of orderLines from the abstract class in the implementation class and point to the implementation of the IOrderLine with annotations?
Thx in advance.
Chillworld
In Java you cannot instantiate an interface.
You can only instantiate actual classes that implement interfaces.
There's actually no such thing as IOrderLine.class.
You probably want to declare your orderLines field in your sub-classes.
In the sub-classes you can declare the field with a concrete class (that will map to a real database table).
If you need/want to use the abstract class to refer to your line items generically (this seems like a really good idea), you could use an abstract method that returns an interface.
Here's an example:
#MappedSuperclass
public abstract class AbstractOrder {
#Id
#GeneratedValue
private Long idOrder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="datum")
private Date date = new Date();
// This abstract method will be implemented by sub-classes
public abstract List<IOrderLine> getOrderLines();
}
Then you can add the fields in your sub-classes and implement the abstract method that returns them:
#Entity
#Table(name = "supplyorderlines")
public class SupplyOrderLine implements IOrderLine, Serializable {
#Id
#GeneratedValue
private Long id;
#OneToMany(targetEntity = SupplyOrderLine.class)
private List<SupplyOrderLine> customerOrderLines;
#Override
public List<IOrderLine> getOrderLines() {
return customerOrderLines;
}
}
If this wasn't about JPA entities, you could also do something like this:
public abstract class PojoClass {
private Long idOrder;
private Date date = new Date();
private List<? extends IOrderLine> orderLines = new ArrayList<? extends IOrderLine>();
}
However, I don't think this is an option in a JPA entity.
That's because your entity class needs to map to a concrete class and database table.

MappedSuperclass - Change SequenceGenerator in Subclass

I'm using JPA2 with Hibernate and try to introduce a common base class for my entities. So far it looks like that:
#MappedSuperclass
public abstract class BaseEntity {
#Id
private Long id;
#Override
public int hashCode() {
// ...
}
#Override
public boolean equals(Object obj) {
// ...
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
}
However, for every table theres a sequence $entityname_seq which I want to use as my sequence generator. How can I set that from my subclass? I think I need to override #GeneratedValue and create a new SequenceGenerator with #SequenceGenerator.
Yes, it is possible. You can override the default generator name with the #SequenceGenerator annotation.
Base class
#MappedSuperclass
public abstract class PersistentEntity implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "default_gen")
protected Long id = 0L;
public Long getId()
{
return id;
}
public void setId(Long id)
{
this.id = id;
}
}
Sequence (SQL)
create sequence role_seq;
Derived class
#Entity
#Table(name = "role")
#SequenceGenerator(name = "default_gen", sequenceName = "role_seq", allocationSize = 1)
public class Role extends PersistentEntity implements Serializable
{
private static final long serialVersionUID = 1L;
#NotNull
#Size(max = 32)
private String name;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
This approach worked fine in Hibernate 4.1.x, but it didn't in EclipseLink 2.x.
edit
As per the comment, it seems to be working with EclipseLink 2.6.1-RC1.
In JPA that cannot be done with annotations. Annotation itself cannot be overridden. Entity inherits all the mapping information from MappedSuperClass. There is only two annotations that can be used to redefine mappings inherited from mapped superClass:
AttributeOverride to override column mappings and
AssociationOverride to override join columns / table.
Neither of them helps with GeneratedValue.
With EclipseLink, you can use a Customizer. DescriptorCustomizer interface defines a way to customize all the information about a jpa descriptor (aka a persistent entity).
public class SequenceCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.setSequenceNumberName(descriptor.getTableName());
}
}
and in your mapped superclass:
#MappedSuperclass
#Customizer(SequenceCustomizer.class)
public abstract class AbstractEntity implements Serializable {
...
}
I'm writing this as it gets too unreadable as the comment on the accepted answer:
I have a BaseEntity that every other Entity inherits from:
BaseEntity.java:
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
private Long id;
I then have two Entities User and Order that both inherit from BaseEntity whilst also having the #SequenceGenerator annotation:
User.java:
#SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_USER", allocationSize = 1)
public class User extends BaseEntity { ... }
Order.java:
#SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ORDER", allocationSize = 1)
public class Order extends BaseEntity { ... }
It works on H2 at least with 2 Sequences SEQ_USER and SEQ_ORDERS:
select SEQ_USER.nextval from dual;
select SEQ_ORDERS.nextval from dual;

How to work with interfaces and JPA

I should start out by saying that I am fairly new to Java EE and that I do not have a strong theoretical background in Java yet.
I'm having trouble grasping how to use JPA together with interfaces in Java. To illustrate what I find hard I created a very simple example.
If I have two simple interfaces Person and Pet:
public interface Person
{
public Pet getPet();
public void setPet(Pet pet);
}
public interface Pet
{
public String getName();
}
And an Entity PersonEntity which implements Person as well as a PetEntity which implements Pet:
#Entity
public class PersonEntity implements Person
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private PetEntity pet;
#Override
public void setPet(Pet pet)
{
/* How do i solve this? */
}
}
#Entity
public class PetEntity implements Pet
{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String name;
/* Getters and Setters omitted */
}
How do I properly handle the case in the setPet method in which I want to persist the relationships between the two entities above?
The main reason I want to use interfaces is because I want to keep dependencies between modules/layers to the public interfaces. How else do I avoid getting a dependency from e.g. my ManagedBean directly to an Entity?
If someone recommends against using interfaces on entities, then please explain what alternatives methods or patterns there are.
You can use targetEntity property in the relationship annotation.
#Entity
public class PersonEntity implements Person {
private Long id;
private Pet pet;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Override
#OneToOne(targetEntity = PetEntity.class)
public Pet getPet() {
return pet;
}
public void setPet(Pet pet) {
this.pet = pet;
}
}

Categories

Resources