Can i user instance method in JPA entity? - jpa

public class Dept{
private String id;
private String name;
private String address;
private List<Student> students;
public static List <Student> getStudentByDeptid(EntityManager em, Dept dept)
{
..............
}
}
getStudentByDeptid() should be static or non static?

Yes you can. But you shouldn't JPA entity are not designed to have business logic in them you should use Session Bans for the same. You can define a StudentBean as session bean and define this logic in that bean.
Assuming you are calling query on em passed to function.

Related

Mapping POJOs and Using Reference in MongoDB using Morphia

I have two model classes. One is Company.java, another is HumanResource.java.
Company.java
#Entity("companies")
public class Company {
#Id
private ObjectId id = new ObjectId();
private String companyName;
private String emailAddress;
private String pictureUrl;
#Reference
private List<HumanResource> humanResources;
...
HumanResource.java
#Entity("humanresources")
public class HumanResource {
#Id
private ObjectId id = new ObjectId();
private String firstName;
private String lastName;
private String emailAddress;
#Reference
private Company company;
...
What I want to achieve is when I save a list of companies to datastore, related list of human resources documents should be inserted automatically.
In addition, I declared
#Id
private ObjectId id = new ObjectId();
in every model class. Is it a good way or should I change it ?
Morphia will not call save() on those references. You must call save() on the instances you want to persist. You can pass in a list of instances so you needn't loop, necessarily, but each instance needs to get passed in explicitly.

spring data jpa fine granular auditing, custom audit

I have requirement where I need to insert user name and group name to which the user belongs (both available in SecurityContext) in the same table.
class Entity
{
#createdBy
String username
#createdBy
String groupname
other fields ...
}
As per requirement. I cant solve this issue by making a user class and referencing it through a foreign key.
With current implementation of AuditingHandler both fields are getting the same value. How do I make sure they get respective values.
Can this be achieved using current implementation ?
If not thn how can I provide custom implementation of AuditingHandler ?
You could make a separate embeddable class and annotate it with #CreatedBy in your parent class. One way is to define a bean implementing AuditorAware, then you can make it return custom object, containing your two required fields. For example, your parent class would look like this (note the listener annotation):
#Entity
#EntityListeners(AuditingEntityListener.class)
public class AuditedEntity {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
#Embedded
#CreatedBy
private AuditorDetails createdBy;
// setters and getters
}
where AuditorDetails is:
#Embeddable
public class AuditorDetails {
private String username;
private String groupname;
// setters and getters
}
and finally, your AuditorAware bean:
#Component
class AuditorAwareImpl implements AuditorAware<AuditorDetails> {
#Override
public AuditorDetails getCurrentAuditor() {
return new AuditorDetails()
.setUsername("someUser")
.setGroupname("someGroup");
}
}
AuditingHandler fetches your custom AuditorDetails from your AuditorAware bean (it must be single bean implementing it) and sets it in your auditable entity.

JPA Mapping embedded fields with createNativeQuery

I have an entity with has a field which represents composite primary key annotated with embeddeid and another field which is annotated with embedded annotation.
Both of these fields are not directly mapped with the the columns returned by the query passed to createNativeQuery method.
The getResultList returns me the list of entities, but the two fields which I mentioned are null in all the entities.
public interface Key{
public int hashCode()
}
#Embeddable
public class CompositePK impements Key{
private int empid;
private Date startdate;
private Date enddate;
}
#Embeddable
public class PartitionKey implements Key{
private String empname;
}
#Entity
public class Employee {
#EmbeddedId
private CompositePK id;
#Embedded
private PartitionKey name;
#Column(name="empid")
private int empid;
#Column(name="empname")
private String empname;
#Column(name="startdate")
private Date startdate;
#Column(name="enddate")
private Date enddate;
}
public class Loader{
private static EntityManager em;
public static void main(String [] args){
//code to instantiate em goes here
//...
//....
Query query = em.createNativeQuery("select empid,empname,startdate,enddate from employees", Employee.class );
List entities = query.getResultList();
//print the list
System.out.println(entities);
}
}
The outcome of this is that the entities are populated but their fieldsid and name which are emdedded fields are null. Can anyone please suggest how to populate these two fields?
Thanks

Mutually referential fields in Play

I am trying to model users with home directories in my system. I got the following model declarations:
#Entity
public class Directory extends Model {
public String name;
#ManyToOne public Directory parent;
#ManyToOne public User owner;
#OneToMany public Set<User> sharees;
}
#Entity
public class User extends Model {
#Unique #Column(unique=true) public String username;
public String password;
public Directory homeDirectory;
public User(String username, String password) {
this.username = username;
this.password = password;
this.homeDirectory = new Directory(username, null, this);
}
}
When I create a user and call .save(), I get an error (A javax.persistence.PersistenceException has been caught, org.hibernate.exception.GenericJDBCException: could not insert: [models.User]). Can anyone explain why?
Using fixtures, can I test this? I'd need to create forward references in my yaml file, but I'm not sure if that's possible.
Thanks,
Vincent.
The error is thrown because of a missing #OneToOne annotation for homeDirectory.
I assume you're creating a directory for each user. If that's the case, then you should also use CascadeType.ALL so these directories automatically get created/deleted when users get created/deleted.
And no Yaml does not support forward references,
so you'll have to work around that when using bidirectional relations.

JPA #OneToMany Mapping Problem

I am trying to do do JPA/Hibernate mappings to map two tables, but am getting this error. any help would be greatly appreciated!!
Restaurants.java
#Entity
#Table(name="RESTAURANTS")
public class Restaurants{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
#OneToMany(mappedBy="restaurant")
private LinkedList<Menus> menus = new LinkedList<Menus>();
/* constructors **/
public Restaurants(){
this.dateJoined = new Date();
};
/* getters and setters **/
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy = "increment")
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public LinkedList<Menus> getMenus() {return menus;}
public void setMenus(LinkedList<Menus> menus) {this.menus = menus;}
}
Menus.java
#Entity
#Table(name = "MENUS")
public class Menus {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private Long restaurantID;
#OneToMany
#JoinColumn(name="restaurant")
private Restaurants restaurant;
/* constructors */
public Menus(){}
/* getters and setters */
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy = "increment")
#Column(nullable = false)
public Long getId() {return id;}
public void setId(Long id) {this.id = id;}
public Long getRestaurantID() {return restaurantID;}
public void setRestaurantID(Long restaurantID) {this.restaurantID = restaurantID;}
public void setRestaurant(Restaurants restaurant) {this.restaurant = restaurant;}
public Restaurants getRestaurant() {return restaurant;}
}
With this error
Exception in thread "main" org.hibernate.MappingException: Could not
determine type for: bb.entities.Restaurants, at table: MENUS, for
columns: [org.hibernate.mapping.Column(restaurant)] at
org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:306) at
org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:290) at
org.hibernate.mapping.Property.isValid(Property.java:217) at
org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:464)
at org.hibernate.mapping.RootClass.validate(RootClass.java:235) at
org.hibernate.cfg.Configuration.validate(Configuration.java:1362) at
org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1865)
at bb.TestMain.setUp(TestMain.java:26) at
bb.TestMain.main(TestMain.java:59)
Thanks.
It appears to be a misconception in the use of the #OneToMany annotation. The #OneToMany annotation is used to represent the 1-side in a 1:M relationship, and the inverse #ManyToOne relationship is used to represent the M-side. Therefore, a #OneToMany annotation should be defined on a collection-type in an entity and not on a normal reference type.
You should therefore:
use a #OneToOne association if that is the nature of the relationship between the entities.
or, decide which entity represents the 1-side in the 1:M relationship. Going by the use of the LinkedList class in Restaurants, I would consider the Restaurants class to be the 1-side, and use the #OneToMany annotation in the Restaurants class, while using the inverse #ManyToOne relationship in the Menus class. The refined code would be:
Restaurants.java
...
#OneToMany(mappedBy="restaurant")
private List<Menus> menus = new LinkedList<Menus>();
Menus.java
#ManyToOne
#JoinColumn(name="restaurant")
private Restaurants restaurant;
Note the change in the declaration of the menus member variable from LinkedList<Menus> to List<Menus>. Apparently, in this case, it is wiser to declare any collection with the interface-type of the collection, instead of the concrete collection class. The rationale is that the underlying JPA provider will use it's own concrete collection types at runtime, for the purpose of proxying the collection values. Hibernate for instance, will use a PeristentList at runtime, to represent the List in a managed entity, and not a LinkedList as created by the entity. If you use the concrete type, Hibernate might fail in mapping the column, or might fail in retrieving the associated records from the database; I'm not sure about the specifics of the runtime behavior, except that I know of the eventual failure.