I have a question about "annotations" in hibernate.
I have a BaseEntity class and another class like state.java who extend
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler", "createdBy", "updatedBy" })
#MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private T id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CreatedBy", nullable = true)
private User createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UpdatedBy", nullable = true)
private User updatedBy;
#Column(name = "createdDate", nullable = true, updatable = false)
private Date createdDate;
#Column(name = "UpdatedDate", nullable = true)
private Date updatedDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "subsite", nullable = true)
private Subsite subsite;
#Column(name = "ip", nullable = true)
private String ip;
#Entity
#Table(name="State")
public class State extends BaseEntity<Long> {
#Column(name = "state", nullable = true)
private String state;
#Column(name = "city", nullable = true)
private String city;
when program creat my tables in DataBase my table'design build like this:
How can I create a table so that the BaseEntity'fields place after state'fields in my Table
Related
I have a set of entities user and conference. I have implemented a method in which I assign users to a conference and save it. However, when I save the conferencce the intermediate table attendance_table is not updated.
My database erd diagram example:
My entities:
#Entity
#Table(name = "user_table", schema = "public")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long user_id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "confirmed")
private boolean confirmed;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.LAZY)
#JoinTable(name = "attendance_table",
joinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "user_id",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "conference_id", referencedColumnName = "conference_id",
nullable = false, updatable = false)})
private Collection<Conference> conferences = new HashSet<>();
#Entity
#Table(name = "conference_table", schema = "public")
public class Conference {
#Id
#Column(name = "conference_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long conference_id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User creator ;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "startConference")
private Date startConference;
#Column(name = "endConference")
private Date endConference;
#ManyToMany(mappedBy = "conferences", fetch = FetchType.LAZY)
private Collection<User> students;
Any ideas? If you need any extra info I can update the question. Thanks in advance!
This was a interesting fix. I was messing around with the user and conference classes and found a solution.
I had to swap the implementations of #ManyToMany of both classes for it to work.
My User class now looks like:
#Entity
#Table(name = "user_table", schema = "public")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long user_id;
#Column(name = "name")
private String name;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
#Column(name = "confirmed")
private boolean confirmed;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.EAGER)
#JoinTable(
name = "user_role_table",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "role_id"))
private Collection<Role> roles = new HashSet<>();
#ManyToMany(mappedBy = "students", fetch = FetchType.LAZY)
private Collection<Conference> conferences;
And my conference class:
#Entity
#Table(name = "conference_table", schema = "public")
public class Conference {
#Id
#Column(name = "conference_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long conference_id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private User creator ;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "startConference")
private Date startConference;
#Column(name = "endConference")
private Date endConference;
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH}, fetch = FetchType.LAZY)
#JoinTable(name = "attendance_table",
joinColumns = {
#JoinColumn(name = "conference_id", referencedColumnName = "conference_id",
nullable = false, updatable = false)},
inverseJoinColumns = {
#JoinColumn(name = "user_id", referencedColumnName = "user_id",
nullable = false, updatable = false)})
private Collection<User> students = new HashSet<>();
Still not exactly sure why it works like this and not the other way around. If anyone knows please explain!
There is my class TableOne.java:
#Table(name = "table_one")
#EntityListeners(AuditingEntityListener.class)
public class TableOne {
#Id
#GeneratedValue(generator = "UUID")
#GenericGenerator(
name = "UUID",
strategy = "org.hibernate.id.UUIDGenerator")
#Column(name = "id", unique = true, nullable = false, updatable = false)
private String id;
#CreatedDate
#Column(name = "created", nullable = false, updatable = false)
private LocalDateTime created;
#LastModifiedDate
#Column(name = "modified", nullable = false)
private LocalDateTime modified;
#Column(name = "status_desc")
private String statusDesc;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(table = "callers")
private Party caller;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(table = "callee")
private Party callee;
...getter/setter
}
And there is Part.java:
#Entity
public class Party {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, nullable = false, updatable = false)
private long id;
#Column(name = "desc")
private String desc;
#Column(name = "ip")
private String ip;
#Column(name = "port")
private int port;
}
The following fields: caller, callee inside TableOne.java contains the same fields (id,desc, port, ip), so I want to keep these in two different tables. For example inside callee and caller tables.
How I can do that?
You can use two entities for that. Simply remove #Entity annotation from Party and annotate it with #MappedSuperclass. Then you can create two entities:
#Entity
#Table(name = "caller")
public class Caller extends Party
and
#Entity
#Table(name = "callee")
public class Callee extends Party
Both will have the same fields, but will be mappet to two different tables.
I have a entity bean with a relation #ManyToOne that is in join on one column.
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) #NotFound (action = NotFoundAction.IGNORE)
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "account", insertable = false, updatable = false, nullable = true)
private AnagraficaClienti account;
And the second Entity
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
....
The "es_account" table has three not nullable primary key(fk_cod_azienda, account, tipo_cli_for) and the relation with the "work_order" table is by account column.
My problem is that sometimes it is possible that the user insert or update WorkOrder with a null account value and that is not avoid by AnagraficaClienti entity because it expects a non null(and not duplicate) value.
Are there any possible way to bypass the join with AnagraficaClienti when account is null?
In my point of view, #ManyToOne is violate OOP design principle due to the creation of redundant relation. Instead, i always create a #OneToMany relation with a list of related entities. To specify the relation as nullable, just add the nullable=true property in #JoinColumn. With #ManyToOne, you must specify property optional=true. Lets try and see if it works.
WorkOrder
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
AnagraficaClienti
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#JoinColumn(name = "account", nullable = true)
private List<WorkOrder> workOrders;
When you want to insert the work order to the database:
workOrderRepository.save(workOrder);
When you want to create the relationship:
AnagraficaClienti client = anagraficaClientiRepository.findById(...);
client.getWorkOrders().add(newWorkOrder);
Is it possible to create one column for bi-directional relationship?
My Entities:
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
Now I see two columns in the database and little bit confused.
I don't want to save the same data but want to display a report about how many users visit on some day.
Update:
You are not required to create a separate field "subscription" in VisitDate class. Hibernate will automatically create a field to store subscription id. The code needs to be slightly changed.
#Entity
#Table(name = "subscription")
public class Subscription {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "associatedSub")
private List<VisitDate> visitDates = new ArrayList<>();
}
Notice, that I have changed the mappedBy property to point at associatedSub in the above class.
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
You can use Uni-Directional relationship for the same purpose. You just need to add a list/set of Visits for a particular subscription, You don't have to create a list of subscription for a particular visit.
for reference Visit [Java JPA] :(https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Undirectional_OneToMany.2C_No_Inverse_ManyToOne.2C_No_Join_Table_.28JPA_2.0_ONLY.29)!
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
}
Need criteria join query for a composite primary key.
Entities:
ArtWork
#Entity
#Table(name = "artwork")
public class ArtWork implements io.malevich.web.entity.Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Id
#Column(name = "language", columnDefinition = "CHAR(2)")
private String language;
#Column(name = "art_name", nullable = false)
private String artName;
#Column(name = "creation_date", nullable = false)
private Date creationDate;
#Column(name = "edition_flag", nullable = false, columnDefinition = "tinyint(1)")
private boolean editionFlag;
#Column(name = "replica_flag", nullable = false, columnDefinition = "tinyint(1)")
private boolean replicaFlag;
#Column(name = "number_of_editions")
private Long numberOfEditions;
#Column(name = "original_id")
private Long originalId;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "category_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Category category;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "gallery_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Gallery gallery;
#ManyToOne
private Specialization specialization;
#ManyToOne
#JoinColumns({
#JoinColumn(
name = "author_id",
referencedColumnName = "id", insertable = false, updatable = false),
#JoinColumn(
name = "language",
referencedColumnName = "language", insertable = false, updatable = false)
})
private Author author;
#Column
private String description;
#Column
private Double price;
//getter setter
}
User:
#javax.persistence.Entity
#Table(name = "user")
public class User implements Entity, UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true, length = 255, nullable = false)
private String name;
#Column(length = 255, nullable = false)
private String password;
#ElementCollection(fetch = FetchType.EAGER)
private Set<Role> roles = new HashSet<>();
#Column(name = "user_type_id")
private Long userTypeId;
#ManyToOne
#JoinColumn(name = "person_id", referencedColumnName = "id")
private Person person;
#ManyToOne
#JoinColumn(name = "organization_id", referencedColumnName = "id")
private Organization organization;
#ManyToOne
#JoinColumn(name = "file_id", referencedColumnName = "id")
private File file;
#Column(name = "activity_flag")
private boolean activityFlag;
//gettter and setter
}
Account States
#javax.persistence.Entity
#Table(name = "account_states")
public class AccountStates implements Entity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(insertable = false, updatable = false)
private String language;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "artwork_id", referencedColumnName = "id"),
#JoinColumn(name = "language", referencedColumnName = "language") })
private ArtWork artwork;
#ManyToOne
#JoinColumn(name = "art_owner_id", referencedColumnName = "id")
private User artOwner;
#Column(name = "quantity")
private Long quantity;
#Temporal(TemporalType.DATE)
#Column(name = "buy_date")
private Date buyDate;
}
Account State Dao:
public class JpaAccountStatesDao extends JpaDao
implements AccountStatesDao {
public JpaAccountStatesDao() {
super(AccountStates.class);
}
#Override
public AccountStates find(Long artOwnerId, Long artworkId, String language) {
final CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder();
final CriteriaQuery<AccountStates> criteriaQuery = builder.createQuery(AccountStates.class);
Root<AccountStates> root = criteriaQuery.from(AccountStates.class);
Predicate p1 = builder.and(builder.equal(root.get("artwork"), artworkId),
builder.equal(root.get("artwork"), language), builder.equal(root.get("artOwner"), artOwnerId));
criteriaQuery.where(p1);
TypedQuery<AccountStates> typedQuery = this.getEntityManager().createQuery(criteriaQuery);
return typedQuery.getSingleResult();
}
}
I want to find Account States where artOwner id = 1 and language = en and artwork id = 1.
Can anyone suggest proper query for the same?
I found a solution for the same, I tried to pass a whole object instead of object id.
So final query is:
#Override
public AccountStates find(User artOwner, Artwork artwork) {
final CriteriaBuilder builder = this.getEntityManager().getCriteriaBuilder();
final CriteriaQuery<AccountStates> criteriaQuery = builder.createQuery(AccountStates.class);
Root<AccountStates> root = criteriaQuery.from(AccountStates.class);
Predicate p1 = builder.and(builder.equal(root.get("artwork"), artwork),
builder.equal(root.get("artOwner"), artOwner));
criteriaQuery.where(p1);
TypedQuery<AccountStates> typedQuery = this.getEntityManager().createQuery(criteriaQuery);
return typedQuery.getSingleResult();
}
}
Now, It works successfully... thanks