I have 2 tables:
#Entity
public class A implements Serializable {
#Column
#NotNull
#Size(min = 1)
#Pattern(regexp = "[A-Za-z]{1}[A-Za-z0-9_]*")
private String token;
#ManyToOne(optional = true)
#JoinColumn(name = "b_id", referencedColumnName = "id")
private B b;
...
}
#Entity
public class B implements Serializable {
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "b")
private List<A> a;
...
}
The Token in entity A should be UNIQUE within B.
For example there is a Token1 within B1 and also a Token1 within B2, but there can
be a second Token1 inside B1.
I'm using JPA with Hibernate.
How do I achieve this?
By creating a UniqueConstraint on the combination of the foreign key and the token.
On entity A, something akin to the following:
#Table(
name="a",
uniqueConstraints={
#UniqueConstraint(columnNames={"b_id", "token"})
}
)
#Entity
public class A implements Serializable {
// ...
}
Related
I have a Class EntityA that contains a List of EntityB.
#Entity
public class EntityA {
#Id
private long id;
#OneToMany(mappedBy = "entityAId", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
public final List<EntityB> listOfB = new ArrayList<>();
...
}
#Entity
public class EntityB {
#Id
private long entityAId;
#Id
private String name;
private String value;
...
}
What I want to do is:
EntityA myEntityA = entityManager.find(EntityA.class, 1);
// myEntityA.listOfB contains one element [entityAId = 1, name = "foo", value = "bar"]
myEntityA.listOfB.clear();
myEntityA.listOfB.add(new EntityB(1, "foo", "baz");
entityManager.persist(myEntityA);
// commit transaction here
But I get "javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session"
Adding an additional unique ID-field in EntityB "fixes" the problem, but I don't want an additional column in my db. Is there a better way?
Is it possible to have multiple #EmbeddedId composite keys defined for a #ManyToOne relationship between classes? Example:
Entity 1
#Entity
#AttributeOverrides({ #AttributeOverride(name="pk.method", column=#Column(name = "http_method", nullable = false)) })
#AssociationOverrides({ #AssociationOverride(name = "pk.operation", joinColumns = #JoinColumn(name = "id_operation", nullable = false)) })
public class Action {
#EmbeddedId
private ActionId pk = new ActionId();
}
#Embeddable
private class ActionId implements Serializable {
#ManyToOne private Operation operation;
private HttpMethod method;
}
Entity 2:
#Entity
#AssociationOverrides
// Need to override the embedded if attributes of the Action entity inside the UserActionId class
public class UserAction {
#EmbeddedId private UserActionId pk = new UserActionId();
}
#Embeddable
private class UserActionId implements Serializable {
// How to provide a #JoinColumn for the Action.pk composite key (action.pk.authURL) and #Column for (action.pk.httpMethod)
#ManyToOne private Action action;
#ManyToOne private User user;
}
Is this possible? I have tried but keep getting a Hibernate error saying that the FK must have the same number of columns as the ActionId pk.
I can't propper map DB tables with JPA annotation.
Tables Subject and Place is ManyToMany through JoinTable.
Subject.java
#Entity
#Table(name = "SUBJECT")
public class Subject implements Serializable {
#Id
#Column(name = "SID")
private Integer sid;
#Column(name = "NAME")
private String name;
// getters and setters
}
SubjectPlace.java
#Entity
#Table(name = "SUBJECT_PLACE")
public class SubjectPlace implements Serializable {
#Id
#Column(name = "SPID")
private Integer spid;
#ManyToOne
#JoinColumn(name = "SUB_KEY") //Subject FK
private Subject subject;
#ManyToOne
#JoinColumn(name = "PLC_KEY") //Place FK
private Place place;
// getters and setters
}
Place.java
#Entity
#Table(name = "PLACE")
public class Place implements Serializable {
#Id
#Column(name = "PID")
private Integer pid;
#Column(name = "NAME")
private String name;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "SUBJECT_PLACE",
joinColumns = { #JoinColumn(name = "PLC_KEY", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "SUB_KEY", nullable = false, updatable = false) })
private Set<Subject> subjects;
// getters and setters
}
But than I need to link Person with Subject in selected Places. I mean that each Place has its own collection of Subject. And a Person have link to Subject whitch resides in particular Place.
like This:
Subject (M) -- (M) Place through JoinTable Subject (1) -- (M) Subject_Place (M) -- (1) Place
Person (M) -- (M) Subject_Place through JoinTable Person (1) -- (M) Person_Subject_Place (M) -- (1) Subject_Place
Person.java
#Entity
#Table(name = "PERSON")
public class Person implements Serializable {
#Id
#Column(name = "PRSID")
private Integer prsid;
#Column(name = "NAME")
private String name;
// How to annotate this code?
// I experience problem in this part of code
#OneToMany
#JoinColumn(name="SPID_KEY")
private List<SubjectPlace> subjectPlaces;
// getters and setters
}
PersonSubjectPlace.java
#Entity
#Table(name = "PERSON_SUBJECT_PLACE")
public class PersonSubjectPlace implements Serializable {
#Id
#Column(name = "PSPID") // Person_Subject_Place ID
private Integer pspid;
#ManyToOne
#JoinColumn(name = "PER_KEY") //Person FK
private Person person;
// How to annotate this code?
// I experience problem in this part of code
#ManyToOne
#JoinColumn(name = "SPID_KEY") //Subject_Place FK
private SubjectPlace subjectPlace;
// getters and setters
}
And when I try so get Persons and its Subjects, I get this error:
Caused by: org.hibernate.MappingException: Foreign key (FK2C3B79384AABC975:PERSON_SUBJECT_PLACE [SPID_KEY])) must have same number of columns as the referenced primary key (SUBJECT_PLACE [PLC_KEY,SUB_KEY])
What, How shoul I map?
In your OneToMany mapping you don't need to specify the foreign key, you just need to use mappedBy property to refer your mapping object, you can learn more about it in OneToMany Mapping Documentation, and here's what you need to map Person and PersonSubjectPlace entities:
In your Person class:
#OneToMany(mappedBy="person")
private List<PersonSubjectPlace> personsubjectPlaces;
In your PersonSubjectPlace class:
#ManyToOne
#JoinColumn(name="PRSID") //Specify the primary key of Person
private Person person;
For further information about the difference between JoinColumn and mappedBy you can take a look at this answer.
EDIT:
For the mapping between SubjectPlace and PersonSubjectPlace:
In your SubjectPlace class:
#OneToMany(mappedBy="subjectPlace")
private List<PersonSubjectPlace> personsubjectPlaces;
In your PersonSubjectPlace class:
#ManyToOne
#JoinColumn(name="SPID") //Specify the primary key of SubjectPerson
private SubjectPlace subjectPlace;
Note:
The best approach to map those classes is to use #JoinTable between Person and SubjectPlace, take a look at this #JoinTable example, because PersonSubjectPlace is pratically an asociation-entity between Person and SubjectPlace.
You should remove #Joincolumn annotation and add mappedBy variable to #OneToMany annotation.
#OneToMany(mappedBy = "spid")
You should have a variable in SubjectPlace that has a Person where you should put #JoinColumn annotation
I am new to hibernate.
I have the following situation,
#Entity(name="A")
Class A {
#Id
int id;
Set<B> listB;
}
#Entity(name="B")
Class B {
#Id
CompositebPK bPk;
}
Class CompositebPK {
#Column(name="id")
int aId;
#Column(name="user_name")
String uname;
}
#Entity (name = "user")
Class User {
#Column (name ="user_name")
String uname;
}
table Structures is as follows,
Table A:
int id
Table B:
int id
String uname
User:
String uname
String password
A to B is 1 to many relation.
B to User is 1 to many.
I want to have the list of B's in A.
What is the best approach to solve the situation?
In the net when I search I am just getting information for inverse join for simple columns, if I try that its not working out, so is there a special way to achieve this?
Try the following mapping configuration:
In the A entity class:
#Entity(name="A")
class A {
#Id
int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "bPk.a")
#Cascade(value = { CascadeType.DELETE })
Set<B> listB;
}
In CompositebPk:
class CompositebPK {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumns({ #JoinColumn(referencedColumnName = "id", nullable = false) })
A a;
#Column(name="user_name")
String uname;
}
I am using:
Spring 3.2
Hibernate 4.1.9
I need to map, with JPA, three classes. Class A has a ManyToMany relationship with Class B. A unique combination of Class A and Class B need to own a collection of Class C.
Table A
foo
id | name
Table B
bar
id | name
Table C
data
id | xrefId
Join Table -- Unique Key on (fooId,barId)
xref
id | fooId | barId
Altering the existing data structure is not an option.
Edit 1:
Goal: Load a Foo, get its collection of Bars. From each Bar, get its (their!) collection of Data.
Class A
#Entity
public class Foo {
#Id
private UUID id;
#ManyToMany(optional = false)
#JoinTable(name = "xref",
joinColumns = { #JoinColumn(name = "fooId") },
inverseJoinColumns = { #JoinColumn(name = "barId") })
private List<Bar> lstBar = new ArrayList<Bar>();
}
Class B
public class Bar {
#Id
private UUID id;
#ManyToMany(mappedBy = "lstBar")
private List<Foo> lstFoo = new ArrayList<Foo>();
}
Class C
public class Data {
#Id
private UUID id;
}
Just KISS. Make another class Xref, which contains id, foo, bar and Set<Data> fields. Make a DAO method to find an Xref using two parameters foo and bar (implement it with a simple HQL). The unique requirement could be achieved by an unique constraint in the database.
It doesn't look good trying to express it just by the class hierarchy, better to use DAOs.
Your join table, xref, has an extra id field, in order to be able to create such a table with JPA you need an extra entity class XRef and then you have to map the relation between A and XRef and betweem B and XRef (both are one-to-many). Then, you can create the entity class C and map the relation between C and XRef. Do you need more help? I don't have time right now to provide the code, but if you need ask and I will try to add it as soon as possible.
Look at this example (used Integer instead of UUID for simplicity, the rest should be OK).
Bar class:
public class Bar {
#Id
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "barId")
private Collection<Xref> xrefCollection;
}
Foo class:
public class Foo {
#Id
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "fooId")
private Collection<Xref> xrefCollection;
}
Xref class:
public class Xref {
#Id
private Integer id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "xrefId")
private Collection<Data> dataCollection;
#JoinColumn(name = "bar_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Bar barId;
#JoinColumn(name = "foo_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Foo fooId;
}
Data Class:
public class Data {
#Id
private Integer id;
#JoinColumn(name = "xref_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private Xref xrefId;
}
This code has been automatically generated by NetBeans, provided that all tables and indexes are correctly defined in the DB