Fetching associated entities with AuditQuery - java

For example I have two entities:
#Entity
#Audited
#Table(....
public class Worker
{
private Long id;
private String name ;
}
#Entity
#Audited
#Table(....
public class Department
{
private Long id;
private String departmentName;
private Worker worker;
}
I want to display the following data for Department:
| departmentName | name (from fetched entityworker) |
When using AuditQuery to get audit information for entity Department, is it possible to fetch the entity Worker to display name value for more human readable display?

This feature is not supported, so you'll have to use a native query and join the actual database tables.

EAGER loading is not supported by envers, all association can only be lazy loaded. An alternative solution to doing joins by hand, is initializing lazy fields of an entity.
My solution to this problem was to go through all fields using java reflection (see), finding proxies by using Hibernate.isInitialized(...) and initializing them with Hibernate.initialize(...).

Related

How to model a three-way relationship in a JPA Spring Boot micro service with a MySQL back end

I have created a Spring Boot JPA micro service with a MySQL back end. I have two simple entities in my model, users and skills. These are used to represent the skills base within my organisation. Each user may have many skills and so I have used a one to many join to model this and can successfully assign skills to users. In my database, I can see that a users_skills table has been created by JPA to achieve this.
However, I am now struggling because, for each skill that a user has, an experience level needs to be specified (e.g. basic, advanced, expert) and I am unsure how to achieve this. I'm not sure whether 'levels' should just be an enum type within the Skill entity, or perhaps it should be a separate entity in its own right? Could I configure JPA so that it generates a users_skills_levels table which would represent this three-way relationship? Any advice would be most welcome!
These are my Entity classes: -
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String name;
private String email;
#OneToMany(
cascade = CascadeType.ALL,
orphanRemoval = true
)
private Set<Skill> skills = new HashSet<>();
getters and setters
}
#Entity
#Table(name = "skills")
public class Skill {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Integer id;
private String name;
getters and setters
}
That's not possible what you try to achieve.
You should create an Entity for the users_skills_levels. E.g. UserSkillLevel This entity will then have a ManyToOne relationship to User and a ManyToOne relationship to Skills plus the attribute level.
The User has a collection of UserSkillLevel and the Skill entity as well.
Please find a more in-depth example here:
https://thoughts-on-java.org/many-relationships-additional-properties/

How can I access the underlying column after defining a #ManyToOne relationship on it in Spring?

I'm using Spring 3.2 with Roo 1.2.3 to build a database-backed Java application via Hibernate. I have several bidirectional OneToMany/ManyToOne relationships among the tables in my database. When I set up the ManyToOne side of the relationship using #JoinColumn (via "field reference" in Roo), a new field whose type is the related entity (the "one" in ManyToOne) is created. However, once this is done, there seems to be no way to access the underlying column value on which the ManyToOne relationship is based. This is a problem when the underlying join column contains data needed by the application (i.e. when the join column contains product stock numbers).
Is there any way to set up my entity class so that the column on which its ManyToOne relationship is based remains accessible without traversing the new join property? How can I define an accessor method for the value of this column?
I've been looking online for an answer to this question for several days, but to no avail. Thanks in advance for your help.
just map the column a second time with insertable=false and updateable=false
To make it more concrete. It's possible to do a HQL-SELCT and restrict a ManyToOne relationship, without any join in the resulting SQL:
Instead of using a join in
session.createQuery("FROM Person person WHERE person.adress.id = 42")
we use can use the adress_idcolumn
session.createQuery("FROM Person person WHERE person.adressId = 42")
This works, if you specify an additional adressId field, which is only used as mapping info for Hibernate:
#Entity
#Access(AccessType.FIELD)
public class Person{
#Id
String id;
#JoinColumn(name = "adress_id")
#ManyToOne(fetch = FetchType.LAZY)
#Nullable
public Adress adress;
#Column(name = "adress_id", insertable = false, updatable = false)
private String adressId;
}
#Entity
#Access(FIELD)
public class Adress{
#Id
String id;
}
The AccessType.FIELD is not needed (But we can leave getters/setters in example). The FetchType.LAZY and #Nullable are also optional, but make it clear when it makes sense to use it. We are able to load Person entities which have a specific Address (we know the address id). But we don't need a join because it's not needed for the WHERE-clause and not for the initial fetch (the address can be fetched lazy).

Toplink JPA Inheritance - Summary/Detail relationship

I'm using toplink JPA in a webapp and I want to map just one table to a class hierarchy. I want to have one class that represents most of the data, and one class that inherits from that (so it gets all the fields of the superclass, plus a couple of other that hold large amounts of data). I don't want the large amounts of data all the time, don't want to hold them in request objects etc. I only want the large bits when someone has selected one of the summaries. I've setup the classes as follows (simplified as an example).
#Entity
#Table(name = "TRANSCRIPTS")
#MappedSuperclass //also tried without this - same error
public class Summary {
#Id
#Column(name = "id")
private long id;
#Column(name = "title")
private String title;
//rest of class etc.
}
#Entity
#Table(name = "TRANSCRIPTS")
public class Detail extends Summary {
#Id
#Column(name = "fullText")
private String fullText;
//rest of class etc.
}
When I try and get data using this hierarchy, I get an error along the lines of
Unknown column 'DTYPE'
So it's looking for a descriminator column. Which I haven't setup, because it's not that sort of relationship.
Is there a different way I can map this summary/detail relationship in JPA? Or should I give up on the class inheritance and have two separate unrelated classes, one representing summary data and one representing the full data (and redefining the summary fields).
Thanks.
DTYPE it is discriminator column that Toplink tries to access to choose between your entities,
If you add that column to your table schema, it will start working.
DTYPE is INTEGER typed column in database.
You could specify your own discriminator column using following code snippet:
#Entity
#DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.INTEGER)
#DiscriminatorValue("1")
class TestClass {}
Here is some documentation for you http://www.oracle.com/technetwork/middleware/ias/toplink-jpa-annotations-096251.html#CHDJHIAG

EJB3/JPA entity with an aggregated attribute

I wanted to know if there is a way to get in a One2Many relationship a field of the One side that is an aggregate of the Many side.
Let's take the following example:
#Entity
public class A {
#Id
private Long id;
#OneToMany (mappedBy="parentA")
private Collection<B> allBs;
// Here I don't know how to Map the latest B by date
private B latestB;
// Acceptable would be to have : private Date latestBDate;
}
#Entity
public class B {
#Id
private Long id;
private Date date;
#ManyToOne (targetEntity=A.class)
private A parentA;
}
My question is how can I make the mapping of the field latestB in the A entity object without doing any de-normalization (not keeping in sync the field with triggers/listeners)?
Perhaps this question gives some answers, but really I don't understand how it can work since I still want to be able to fetch all childs objects.
Thanks for reading/helping.
PS: I use hibernate as ORM/JPA provider, so an Hibernate solution can be provided if no JPA solution exists.
PS2: Or just tell me that I should not do this (with arguments of course) ;-)
I use hibernate as ORM/JPA provider, so an Hibernate solution can be provided if no JPA solution exists.
Implementing the acceptable solution (i.e. fetching a Date for the latest B) would be possible using a #Formula.
#Entity
public class A {
#Id
private Long id;
#OneToMany (mappedBy="parentA")
private Collection<B> allBs;
#Formula("(select max(b.some_date) from B b where b.a_id = id)")
private Date latestBDate;
}
References
Hibernate Annotations Reference Guide
2.4.3.1. Formula
Resources
Hibernate Derived Properties - Performance and Portability
See,
http://en.wikibooks.org/wiki/Java_Persistence/Relationships#Filtering.2C_Complex_Joins
Basically JPA does not support this, but some JPA providers do.
You could also,
- Make the variable transient and lazy initialize it from the OneToMany, or just provide a get method that searches the OneToMany.
- Define another foreign key to the latest.
- Remove the relationship and just query for the latest.

Does JPA support mapping to sql views?

I'm currently using Eclipselink, but I know now days most JPA implementations have been pretty standardized. Is there a native way to map a JPA entity to a view? I am not looking to insert/update, but the question is really how to handle the #Id annotation. Every entity in the JPA world must have an ID field, but many of the views I have created do not conform to this. Is there native support for this in the JPA or do I need to use hacks to get it to work? I've searched a lot and found very little information about doing this.
While using the #Id annotation with fields of directly supported types is not the only way to specify an entity's identity (see #IdClass with multiple #Id annotations or #EmbeddedId with #Embedded), the JPA specification requires a primary key for each entity.
That said, you don't need entities to use JPA with database views. As mapping to a view is no different from mapping to a table from an SQL perspective, you could still use native queries (createNativeQuery on EntityManager) to retrieve scalar values instead.
I've been looking into this myself, and I've found a hack that I'm not 100% certain works but that looks promising.
In my case, I have a FK column in the view that can effectively function as a PK -- any given instance of that foreign object can only occur once in the view. I defined two objects off of that one field: one is designated the ID and represents the raw value of the field, and the other is designated read-only and represents the object being referred to.
#Id
#Column(name = "foreignid", unique = true, nullable = false)
public Long getForeignId() {
...
#OneToOne
#JoinColumn(name = "foreignid", insertable=false, updatable=false)
public ForeignObject getForeignObject() {
...
Like I said, I'm not 100% sure on this one (and I'll just delete this answer if it turns out not to work), but it got my code past a particular crash point.
Dunno if it applies to your specific situation, though. And there's an excellent chance that after 11 months, you no longer care. :-) What the hell, that "Necromancer" badge doesn't just earn itself....
In my view I have a "unique" id, so I mapped it as the Entity id.
It works very well:
#Entity
#Table(name="table")
#NamedQuery(name="Table.findAll", query="SELECT n FROM Table n")
public class Table implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="column_a")
private int columnA;
JPA - 2.5.4
CREATE MATERIALIZED VIEW IF NOT EXISTS needed_article as select product_id, count(product_id) as count from product_article group by product_id;
CREATE MATERIALIZED VIEW IF NOT EXISTS available_article as select product_id, count(product_id) as count from article a inner join product_article p
on a.id = p.article_id and a.stock >= p.amount_of group by product_id;
CREATE UNIQUE INDEX productId_available_article ON available_article (product_Id);
CREATE UNIQUE INDEX productId_needed_article ON needed_article (product_Id);
Entity.java
#Entity
#Immutable // hibernate import
#Getter
#Setter
public class NeededArticle {
#Id
Integer productId;
Integer count;
}
Repository.java
#Repository
public interface AvailableProductRepository extends CrudRepository<AvailableArticle, Integer> {
#Query("select available.productId from AvailableArticle available, NeededArticle needed where available.productId = needed.productId and available.count = needed.count")
List<Integer> availableProduct();

Categories