This is in continuation with this question I asked a yesterday. After going through various resources and consulting people, I was not able to find any JPA annotations supporting API, for mapping units of measurement. So, I decided to go with creating it myself.
Based on various patterns on Observations and Measurements described by Martin Fowler in his book - Analysis Patterns: Reusable Object Models, I tried to create a basic implementation to meet my needs. I've created two entities, Unit and Quantity, as below: -
Unit entity: -
#Entity
#Table(name = "unit")
public class Unit {
#Id
#Column(name = "symbol")
private String symbol;
#Column(name = "name")
private String name;
#Column(name = "multiplier")
private Number multiplier;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "symbol")
private Unit baseUnit;
public Unit() {
}
public Unit(String symbol, String name, Number multiplier, Unit baseUnit) {
this.symbol = symbol;
this.name = name;
this.multiplier = multiplier;
this.baseUnit = baseUnit;
}
/** Getters and Setters **/
}
Quantity Entity: -
#Entity
#Table(name = "quantity")
public class Quantity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int quantityId;
private Number amount;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "unit")
private Unit unit;
public Quantity() {
}
public Quantity(Number amount, Unit unit) {
this.amount = amount;
this.unit = unit;
}
/** Getters and Setters **/
}
And in Item entity, I'm having a reference of Quantity entity, to represent my unitOfIssue and unitOfPurchase. And then, wherever I've to deal with some quantity, I'll have this Quantity reference.
Now, here's the problem I'm facing now. Since Quantity class here will be an entity. So, we have to map it to a DB Table. So, the caveat here is, everytime I want to add some quantity, or update the quantity, an entry will go in the Quantity table first, and then it will be updated in the Item table. I think, the problem is pretty clear. We would have huge entry in the Quantity table, which clearly shows a bad design.
Can someone give an insight on the approach and what options I've while I implement this pattern in JPA? And how can I solve the problem?
I would recommend this instead. Since units of measure are unlikely to change often, it is worth building them into the code. That way you can meaningfully use the values in the program itself.
It also makes the database more cohesive if it will ever be used anywhere else. You can also extend Quantity to be things LinearQuantity, ArealQuantity, VolumetricQuantity (etc.) to make sure someone isn't trying to buy 30 feet of oil.
#Embeddable
public class Quantity{
public enum Unit {FEET,METERS,INCHES,MM}
#Enumerated( value = EnumType.STRING)
private Unit unit;
private Number amount;
public Quantity() {
}
}
#Entity
Public Class PurchaseOrder
{
#Embedded
#AttributeOverrides({
#AttributeOverride(name="unit", column=#Column(name="UNIT")),
#AttributeOverride(name="amount", column=#Column(name="AMOUNT"))
})
private Quantity quantity;
....
}
You need a master table of units which will have all the units as they are fixed so you can create simple script to populate it.
For Quantity I will not recommened a seperate entity it can be property to transaction table which can simply establish relation between Item its quantity and unit and you can do that with #OneToOne with Unit Entity.
Here is the sample example
#Entity
Public Class PurchaseOrder
{
#OneToOne
private Unit unitOfPurchase;
#OneToOne
private Unit unitOfIsuse;
-- Quanity number here ---
}
You should use Cascade very carefully for master tables.
Check out this JPA library for the popular JScience project: JScience-JPA
Based on similar support for Java Monetary types (JSR 354) we also plan to add something similar for JSR 363
Related
I use crnk (JSON-API) in java project and I have 3 questions regarding its usage with spring boot and jpa - haven't found exact implementation details in documentation.
For example, I have 2 entities and respective tables:
#Entity
#JsonApiResource(type = "employee")
public class Employee {
#Id
#JsonApiId
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "typeId")
private EmployeeType employeeType; //stored in table as typeId
}
#Entity
#JsonApiResource(type = "type")
public class EmployeeType {
#Id
#JsonApiId
private int id;
private String typeName;
private int salary;
}
How should JsonApiRelation be introduced in order to be able to call "/employee/1" and "/employee/1/type" urls?
For example there is one more entity.
#Entity
#JsonApiResource(type = "project")
public class Project {
#Id
#JsonApiId
private int id;
private String supervisorName;
private String projectName;
}
First, I'd like to have List of Projects for each Employee, where he is a supervisor, joint by name and have it listed as attribute in Json.
Tried implementing it with #OneToMany and #JoinColumn annotations but got StackOverflowException. How could this be implemented. And second, how could this be implemented with Relation? Like "/employee/1/projects" url.
How should I implement custom filtering of results for findAll method? For example, I have a List of all Employees, but I'd like to exclude some of them from the response. Which class/method should be introduced for this behaviour?
#JsonApiRelation annotation should not be necessary. Crnk will detect the #ManyToOne annotation and map it accordingly.
in case of crnk-jpa it is sufficient to specify all relationships in JPA. Matching JSON API relationships. So your approach seems good. What was the StackoverflowException stacktrace? (next to the examples, there are also many example entities in crnk-jpa)
I would make use of a decorator. See http://www.crnk.io/documentation/#_request_filtering. RepositoryDecoratorFactory allows to place a custom repository between the caller and crnk-jpa (or any other kind of repository). There you can do any kind of modification perform (maybe) calling the "real" repository. => Will add an example for this
feel free also make open up tickets in crnk for any documentation/example clarifications.
I'm trying to build a Spring Boot data layer on top of another project's DB. I'm want to get to a point where I can consume their data via Restful endpoints rather than directly from the DB. Maximum abstraction is the goal. Here's my problem. Consider the following JPA entity:
#Entity
#Table(name = "PERSON", schema = "public")
public class Person {
#Id private long id;
private String name;
private long favoriteFood;
private Address address;
//Getters, Setter etc.....
}
Notice that favoriteFood is a long, not a String. This is because the DB uses a lookup table. Let's say Joe's favorite food is pizza. The person table stores a 1 in the favorite_food column which is the fk to the "pizza" value stored in the food_ref table. This pattern is repeated hundreds or times in the DB. What is the best way to model this in JPA/Hibernate? Change the variable to String and have the getter and setter do the lookup? I've not found any examples which seems strange. This is a common DB structure. Any advice on best practices would be appreciated. Thanks!
The best way in this scenario is to use one to one relationship in the JPA entity with the FoodRef class
#Entity
#Table(name = "PERSON", schema = "public")
public class Person {
#Id private long id;
private String name;
#OneToOne(fetch=FetchType.LAZY)
#JoinColumn(name="food_ref_id")
private FoodRef favoriteFood;
private Address address;
//Getters, Setter etc.....
}
The strategy I'm taking to implementing a maker-checker scenario is through using multiple tables. Currently, I'm using Hibernate 4.2 (annotations). The following scenario is what I would like to achieve. However, I'm having problems with the multi-level inheritance.
The basic idea is that there are two tables (pending and approved). When an add() occurs, the entry is inserted into the pending table. When that entry is approved, it is removed from the pending table and inserted into the approved table.
Policy (the policy)
|
+ -- Pending (maker information)
|
+ -- Approved (checker information)
So, class Policy is the class that defines the necessary fields for a policy. To keep this post shorter, the fields are not be shown.
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) // problem
public abstract class Policy { ... }
The Pending class is for the newly-added Policy that is awaiting approval and it has information on the maker/adder.
#Entity
#Table(name = "pending")
public class Pending extends Policy {
#Column(name = "adder", ...)
private String adder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "time_added", ...)
private Date timeAdded;
}
The Approved class is for approved entities and it contains additional information on the approver in addition to the information from the Pending class.
#Entity
#Table(name = "approved")
public class Approved extends Pending {
#Column(name = "approver", ...)
private String approver;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "time_approved", ...)
private Date timeApproved;
}
My first thought was to try TABLE_PER_CLASS. However, it resulted in the following runtime error: org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: .... The solution for this is to modify the base class #GeneratedValue(strategy = GenerationType.IDENTITY) to #GeneratedValue(strategy = GenerationType.TABLE). However, modifying that class is beyond my scope as it is shared across multiple projects.
Just for the heck of it, I tried the other two strategies. Obviously, SINGLE_TABLE resulted in one table, with an extra column DTYPE. Not what we wanted. JOINED resulted in two tables, but the approved table has a foreign key to the pending table. Since we wanted to remove an entry from the pending table and move it to the approved table, this would not work for us.
Currently, my solution is to as follows, which is basically copy and paste the code from the Pending class into the Approved class.
#Entity
#Table(name = "approved")
public class Approved extends Policy {
#Column(name = "adder", ...)
private String adder;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "time_added", ...)
private Date timeAdded;
#Column(name = "approver", ...)
private String approver;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "time_approved", ...)
private Date timeApproved;
}
This solution seems counter-intuitive as it duplicates code. Is there a solution that does not require code duplication and keeps the maker-checker process that way it currently works?
After experimenting with the suggested approach by #kostja, I arrived at the following solution.
The maker class encapsulates information pertaining to the maker, which is also an #Embeddable class.
#Embedabble
public class Maker {
#Column(name="maker_id", ...)
private String makerId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="time_added", ...)
private Date timeAdded;
}
Similarly, the checker class also encapsulates information pertaining to the checker, which is also an #Embeddable class.
#Embedabble
public class Checker {
#Column(name="checker_id", ...)
private String makerId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="time_approved", ...)
private Date timeApproved;
}
The payload is an #Embeddable class. By making the payload an #Embeddable class, the Maker and Checker can be reused for multiple payloads.
#Embeddable
public class Payload { ... }
For example, given two different payloads that requires maker/checker. One of the payload requires 2 checker.
#Embeddable
public class PayloadA { ... }
#Embeddable
public class PayloadB { ... }
Then we define the following two tables for PayloadA.
#Entity
#Table("a_pending")
public class PendingA {
#Embedded
private PayloadA payload;
#Embedded
private Maker maker;
}
#Entity
#Table("a_approved")
public class ApprovedA {
#Embedded
private PayloadA payload;
#Embedded
private Maker maker;
#Embedded
private Checker checker;
}
Similarly, for PayloadB define two tables. And PayloadB requires two checkers.
#Entity
#Table("b_pending")
public class PendingB {
#Embedded
private PayloadB payload;
#Embedded
private Maker maker;
}
#Entity
#Table("b_approved")
public class ApprovedB {
#Embedded
private PayloadB payload;
#Embedded
private Maker maker;
#Embedded
#AttributeOverrides(value = {
#AttributeOverride(name="checkerId",column="checker1_id"),
#AttributeOverride(name="timeApproved",column="checker1_time_approved"),
})
private Checker checker1;
#Embedded
#AttributeOverrides(value = {
#AttributeOverride(name="checkerId",column="checker2_id"),
#AttributeOverride(name="timeApproved",column="checker2_time_approved"),
})
private Checker checker2;
}
I hope this solution should be general and flexible enough.
I would use a different approach for this. I assume Policy is your entity - the one carrying the real payload. You would like to add some metadata to it. Inheritance does not look as a good fit for this to me. A Pending is not an Policy and an Approved is not a Pending.
Instead of inheritance, I would model the metadata as separate, unrelated entities and create 1-1 relationships to the payload entity. Or many-to-one, if you need multiple approvals.
This way, you have a better decoupled data model and a more normalized DB structure. This gives you more flexibility. You can have single or multiple approvals, change the Approval model without changing the payload entity, and have a better focused payload entity, unburdened by metadata.
The entities could look like this:
#Entity
public class Policy{
#OneToOne
private Creation creation;
#OneToMany(mappedBy="policy")
private List<Approval> approvals;
...
}
Creation:
#Entity
public class Creation{
#OneToOne
private Policy policy;
private String creator;
#Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
...
}
Approval:
#Entity
public class Approval {
#ManyToOne
private Policy policy;
private String approver;
#Temporal(TemporalType.TIMESTAMP)
private Date approvedAt;
..
}
What I currently have:
#Entity
public class Payment {
#Id #GeneratedValue
private long id;
#Column(unique = true)
private Date period; // Only used for year and month
...
}
#Entity
public class Department {
#Id #GeneratedValue
private long id;
...
}
The Payment entity just holds default payments that need to be paid by all departments only once pear year and month. There is no relationship needed for between them as all Departments pay all Payments.
What I want to achieve:
I want to distinguish between the currently shared payments and some other Department specific payments. So a Department will be able to choose to use all the shared payments (as it is currently designed) or define its own payments and not use any of the other ones.
The company Payments should keep working in the same way and I have to make sure that the Department payments are unique for each department too.
In OOP terms, I think I need to model any of the following options:
Probably the first one would be more appropriate.
Note I can't change the way any entity is currently identified. However, I can add uniqueness on any other fields.
Questions:
What would be the appropriate way to do this in JPA2?
Is a Payment hierarchy the way to go? How should it be mapped to make sure the unique
fields don't collide?
Is there any way to avoid the hierarchy?
I think the scenario does require a relationship:
#Entity
public class Payment {
#Id #GeneratedValue
private long id;
#Column(unique = true)
private Date period; // Only used for year and month
#ManyToOne
private Department department;
}
This would allow any type of payment to be created for any department. As far as default payments for a department, I think that is outside the responsibility of the ORM and should be handled within the business logic.
If I understood you correctly, you need to achieve uniqueness per department. It's possible using compound id.
Some points:
if you want to use compound keys(period+department_id) you have to set them both and your default payments should have 1 common fake Department to which all default payments will belong to.
In general case I would follow Kevin's approach. It's easy and less error-prone. Anyway you decide.
#Entity
public class Payment implements Serializable {
#EmbeddedId
private Period period;
}
#Embeddable
public class Period implements Serializable {
#ManyToOne
private Department department;
private Date period;
}
#Entity
public class Department implements Serializable {
#Id#GeneratedValue
private long id;
#OneToMany
private List<Payment> payments = new ArrayList<Payment>();
}
I haven't been able to keep the PK in my Payment entity and also maintain a unique index on both Period and Department. In DB terms I'm looking for these:
Payment(ID, Period, FK_Department)
And this table should be added a unique index in Period and FK_Department that would allow nulls in FK_Department (as you can see a compound PK is not an option here for that reason and because I need to keep the same PK structure used). With that table, all Payments with null FK_Department value will be the generic/default/company payments while the ones with a non-null FK_Department will be the ones that a particular department has assigned, so it will use those instead of the company ones.
Due to my lack of knowledge of JPA I couldn't manage to replicate this schema. However, I could create a similarly functional schema. This is the best I came up with so far:
With its obviously awful period duplication I can manage to create two unique index for each table: one for the Period of the CompanyPayment entity and one for the Period and Department pair of the DepartmentPayment entity:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Payment {
#Id #GeneratedValue
private long id;
...
}
#Entity
public class CompanyPayment extends Payment {
#Column(unique = true)
public Date period;
...
}
#Entity
#Table(uniqueConstraints =
#UniqueConstraint(columnNames = { "period", "department_id" })
)
public class DepartmentPayment extends Payment {
public Date period;
#ManyToOne(optional = false)
#JoinColumn(name = "department_id")
private Department department;
...
}
I will be using this solution for now but I'm open to any other better solution.
I am trying to model such situation - there is a cash transfer (I mean a car that carries money), that has required amounts of each currency, and also an actual amount for each currency. And it seems to me pointless to create two separate classes, one for required amount and another for actual amount. So the implementation would look like this:
#Entity
public class CashTransferCurrencyAmount {
// id, version and so on
#Column(length = 3)
private String currencyCode;
#Basic
private BigDecimal amount;
#ManyToOne
private CashTransfer cashTransfer;
}
#Entity
public class CashTransfer {
// id, version and so on
#OneToMany(mappedBy="cashTransfer")
private Set<CashTransferCurrencyAmount> requiredCurrencyAmountSet = new HashSet<CashTransferAmountCurrency>();
#OneToMany(mappedBy="cashTransfer")
private Set<CashTransferCurrencyAmount> actualCurrencyAmountSet = new HashSet<CashTransferAmountCurrency>();
}
But how is a CashTransferCurrencyAmount instance to know to which collection it belongs? I have two ideas:
1 - add a discriminator field to CashTransferCurrencyAmount:
public enum RequestType {
ACTUAL,
REQUIRED
}
#Basic
#Enumerated(EnumType.STRING)
private RequestType requestType;
and add #WHERE annotations to collections in CashTransfer. This is preferable for me.
2 - create two join tables. one for mapping requested amounts and one for mapping actual amounts. I dislike this one as I don't want too many tables in my DB.
Are there any other ways to achieve this? I this approach correct?
And please don't tell me to put both requested and actual amounts in one entity. The real case is more complicated, each CashTransferCurrencyAmount has it's own collections so it can't be solved that way.
EDIT
As for requests for complete story - there used to be two values in CashTransferCurrencyAmount - required (I think it should be 'requested') and actual, but now each amount has it's own collection - how this amount is split into denominations. So I need a collection of amounts, each one having a collection of denominations. The type of CurrencyAmount and CurencyDenomination seems to be the same for requested ones and for actual ones.
Since you want CashTransferCurrencyAmount instance to know which collection it belongs to, I assume you want to have some logic based on that. The way I would model your situation would be using inheritance.
You're saying "it seems to me pointless to create two separate classes", I would however try to convince you that you should. You could use a "Single Table" inheritance type, so that you don't introduce additional tables in your DB, which is what you're trying to accomplish.
My shot would look something like:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "request_type", discriminatorType = DiscriminatorType.STRING)
public abstract class CashTransferCurrencyAmount {
// id, version and so on
#Column(length = 3)
private String currencyCode;
#Basic
private BigDecimal amount;
#ManyToOne
private CashTransfer cashTransfer;
}
#Entity
#DiscriminatorValue("REQUIRED")
public class CashTransferCurrencyAmountRequired extends CashTransferCurrencyAmount {
// required anount specific stuff here
}
#Entity
#DiscriminatorValue("ACTUAL")
public class CashTransferCurrencyAmountActual extends CashTransferCurrencyAmount {
// actual anount specific stuff here
}
#Entity
public class CashTransfer {
// id, version and so on
#OneToMany(mappedBy="cashTransfer")
private Set requiredCurrencyAmountSet = new HashSet();
//Stackoverflow deleting my generic sets! But it's exactly the same as in your code...
#OneToMany(mappedBy="cashTransfer")
private Set actualCurrencyAmountSet = new HashSet();
}