The entity describing the machine
#Entity
#Table(name = "machine")
public class Machine {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "machine_node", joinColumns = #JoinColumn(name = "machine_id"), inverseJoinColumns = #JoinColumn(name = "node_id"))
private List<NodeMachine> nodeMachines = new ArrayList<>();
}
The entity describing the part/node
#Entity
#Table(name = "node_machine")
public class NodeMachine {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
Several parts are installed on each machine (nodeMachines list), and each part can be installed on different machines, so ManyToMany was added.
For example, a wheel can be mounted on a motorcycle or a car. A motorcycle can have two wheels, and a car can have four.
I will describe in more detail what is in the tables. I must say right away that the example is not very successful, just for understanding. In the Machine table we have 100 M motorcycles (1-100) and 100 C cars (1-100). And there is only one entry in the NodeMachine table - the K1 wheel, which is suitable for all one hundred motorcycles and for all one hundred cars. From this, there is no way to determine how many wheels each motorcycle and each car should have. Therefore, I believe that there should be a third table where the number of wheels is indicated for each car and motorcycles. And I think it's too redundant to keep 200 records of wheels for motorcycles and 400 records for cars in the table.
Each part is installed on a specific machine in a certain number.
I want to get the number of nodes installed in a particular machine by knowing the node and machine name.
To do this, you will have to create another count_machine_node table with the fields
- machine_id
- node_id
- count
I understand that you will have to create a new entity.
#Entity
#Table(name = "node_machine")
public class CountNodeMachine {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long machine_id;
private Long node_id;
private Integer count;
}
But what connections do you need to register in these entities?
How to link these three tables correctly?
And do I need to create a CountNodeMachine entity?
Please comment if this serves the purpose.
Machine entity:
#Entity
#Table(name = "machine")
public class Machine {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy="machineId")
List<MachinePartCount> count;
Part entity
#Entity
#Table(name = "part")
public class Part {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#OneToMany(mappedBy="partId")
List<MachinePartCount> count;
Relation entity
#Entity
#Table(name="machine_part")
#IdClass(MachinePartCountPK.class)
public class MachinePartCount {
#Id
private Integer machineId;
#Id
private Integer partId;
private Integer count;
Composite Key
#Embeddable
public class MachinePartCountPK implements Serializable{
private static final long serialVersionUID = 1L;
private Integer machineId;
private Integer partId;
output:
**machineService.findAll()**
getAllMachines: [Machine [id=1, name=m1, count=[MachinePartCount [machineId=1, partId=1, count=2]]], Machine [id=2, name=m2, count=[MachinePartCount [machineId=2, partId=102, count=4]]]]
**partService.findAll()**
getAllParts: [Part [id=1, name=p100, count=[MachinePartCount [machineId=1, partId=1, count=2]]], Part [id=102, name=p10, count=[MachinePartCount [machineId=2, partId=102, count=4]]]]
**machinePartCountService.findAll()**
getmachinePartEntries: [MachinePartCount [machineId=1, partId=1, count=2], MachinePartCount [machineId=2, partId=102, count=4]]
Data in tables:
machine table:
machine
part table:
part
machine_part table:
machine_part
I always suggest to start development from the Java side. So, it might be something like
#Entity
#Table(name = "machine")
public class Machine {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Список узлов машины
#ElementCollection
private Map<NodeMachine, Integer> nodeMachines = new HashMap<>();
}
Also, check my Hibernate articles (Russian and English versions)
You don't need the third entity, as you can do the sql query, or select machine by name, filter it's nodeMachines list and count the result.
For example, using the repository, like here you can select machine by id, or a list of machines by name, and then just filter it's(their's) node lists by name and count.
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface MachineRepository extends CrudRepository<Machine, Long> {
List<Machine> findByName(String lastName);
}
And somewhere in your code:
#Autowired
private MachineRepository machineRepository;
public int countNodesInMachine(String machineName, String nodeName) {
return machineRepository.findByName(machineName).stream()
.flatMap(machine -> machine.getNodeMachines().stream())
.filter(node -> node.getName().equals(nodeName))
.count();
}
To do this, you can create a counter in the NodeMachine entity. This is economical in terms of occupied space in the database, but not true in terms of object orientation. Using the CountNodeMachine entity is not economical at all because a table is wasted to hold a number. I think you need a wrapper class that has NodeMachine and its counts. and use List of this to Machine Entity.
If I get from the above example,
You can do is create a third entity namely as Categories.
As you have a machine specific category, like Motorcycles or Car.
They have a specific set of wheels.
You can map that in this third table and create relation with the Machine.
`Categores
id| category| wheels| othernodes
1 | Car | 4 | 1
2 | Bike | 2 | 3`
and so on, you just will have to find the category and node from the machine table and get the count easily, also you can add new nodes for the same.
The only downside is that you machine will be specific to Category.
Hello programming council, this is my first use of JPA in anger.
I have 2 Tables:
Entity
#Table(name="category")
public class Category {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#Column(name="category")
private String category;
#Column(name="budget")
private double budget;
#Column(name="savings")
private String savings;
#Column(name="archive")
private String archive;
Entity
#Table(name="Transaction")
public class Transaction {
#Id
#Column(name="transaction_no")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long transactionNo;
#Column(name="transaction_date")
private String transactionDate;
#Column(name="transaction_category")
private String transactionCategory;
#Column(name="transaction_description")
private String transactionDescription;
#Column(name="transaction_amount")
private double transcationAmount;
#Column(name="transaction_auto")
private String transactionAuto;
I want to create a new object called Tile which will contain String category and String balance, the SQL for which would be:
select t.transaction_category as category, sum(t.transaction_amount) as balance
from budgeteer.category c
join budgeteer.transaction t
on c.category = t.transaction_category
group by t.transaction_category;
What is the easiest/best way for me to accomplish this?
Thanks in advance.
Ok, so after a little more research, I discovered that I could actually just do this with the same Entity, repository and service without generating a table. You just need to leave out the #Table annotation when you create your entity.
I want to compare two attributes using JPA method convention.
This is my class
#Entity
#Table(name = "aircrafts")
public class Aircrafts {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Size(max = 45)
#Column(name = "number", length = 45)
private String number;
#Column(name = "capacity")
private int capacity;
#Column(name = "seats_taken")
private int seatsTaken;
}
And this the method I want to implement :
public interface AircraftsRepository extends JpaRepository<Aircrafts, Long> {
public List<Aircrafts> findBySeatsTakenLessThanCapacity();
}
However I got this exception:
PropertyReferenceException: No property lessThanCapacity found for type int! Traversed path: Aircrafts.seatsTaken.
I've tried using int and Integer but I got the same exception. Which is the correct method name?
I think #benji2505, correctly mentioned that the data model mixes things that "should" be in different tables. Normally one would expect two tables: Aircrafts, Flights.
Then you could easily use:
List<Flight> flightsWithFreeSeats = aircraftRepository
.findAll()
.stream()
.map(aircraft ->
flightRepository.findByAircraftAndSeatsTakenLessThen(aircraft, aircraft.getCapacity)
)
.collect(Collectors.toList)
With current model probably #JZ Nizet already posted the best answer in his comment.
I am trying to use hibernate annotations for getting data from a MySQL database table which doesn't have a primary key defined.
However the fact is 2 columns of that table together are unique in the table. How can I achieve the same using hibernate annotation?
This is my code
#Entity
#Table(name = "coc_order_view")
public class CoCOrderDetailsTest {
#EmbeddedId
private MyJoinClassKey key;
#Column(name = "coupon_code")
private String couponCode;
some other columns and their getters and setters .....
#Embeddable
public class MyJoinClassKey implements Serializable {
private static final long serialVersionUID = -5L;
#Column(name = "product_id")
private int productId;
#Column(name = "order_id")
private int orderId;
gettes and setters....
And here is my criteria query
Criteria criteria = getHibernatetemplate().getSession().createCriteria(CoCOrderDetailsTest.class);
criteria.add(Restrictions.eq("status", "New"));
ArrayList<CoCOrderDetailsTest> orderDet = (ArrayList<CoCOrderDetailsTest>) getHibernatetemplate().get(criteria);
I am unable to get all the values from db. Kindly suggest some solutions.
After reading through your question again not sure this will help. You can't have a table without primary key(s). Read the first couple of paragraphs in this article
That said, if you can alter the table and add primary keys on those fields you need to add #IdClass annotation to your class signature for CoCOrderDetailsTest and then get rid of the #embeddable and #embeddedId notation in your classes.
Another alternative, if you can add a field to the table, would be to use an #GeneratedValue on that added primary key field and of course annotate it with #Id.
If you can't alter the table then you can't use JPA and you'll have to use JDBC.
See http://docs.oracle.com/javaee/5/api/javax/persistence/IdClass.html
A working example:
#Entity
#Table(name = "player_game_log")
#IdClass(PlayerGameLogId.class)
public class PlayerGameLog {
#Id
#Column(name = "PLAYER_ID")
private Integer playerId;
#Id
#Column(name = "GAME_ID")
private String gameId;
....
and the id class (note there are no annotations on the id class)....
public class PlayerGameLogId implements Serializable {
private static final long serialVersionUID = 1L;
private Integer playerId;
private String gameId;
Try:
String hql = "FROM CoCOrderDetailsTest WHERE status = :status";
Query query = session.createQuery(hql);
query.setParameter("status","New");
List results = query.list();
I usually use EntityManager rather than session so I'm not familiar with this syntax - and I have typically added a type to the list to be returned - like:
List<CoCOrderDetailsTest> results = query.list();
I am using Sprind JPA, Spring 3.1.2(in future 3.2.3), Hibernate 4.1 final.
I am new to Sprind Data JPA. I have tow Table Release_date_type and Cache_media which entities are as follows :
ReleaseAirDate.java
#Entity
#Table(name = "Release_date_type")
public class ReleaseDateType {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer release_date_type_id;
#Column
private Integer sort_order;
#Column
private String description;
#Column
private String data_source_type;
#Column(nullable = true)
private Integer media_Id;
#Column
private String source_system; with getters and setters..
and CacheMedia as
#Entity
#Table(name = "Cache_Media")
public class CacheMedia {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private Integer id;
#Column(name="code")
private String code;
#Column(name="POSITION")
private Integer position;
#Column(name="DESCRIPTION")
private String media_Description; with setter and getters.
Now my repository interface is as follows :
public interface ReleaseDateTypeRepository extends CrudRepository<ReleaseDateType, Long>{ }
Now i want to write a method(Query) in ReleaseDateTypeRepository interface which can get all the data from Release_Date_Type table including appropriate media_description from Table 'Cache_Media' based on media_id of Release_date_type table.
So my select (SQL)query looks like
SELECT * from Release_Date_Type r left join Cache_Media c on r.media_id=c.id
I don't know how to map entities.
I tried so many thing but not luck.
Any help is appreciated.
Its not the answer for joining via Hibernate, but alternatively you can create a view with your join and map the view to your objects