I have these 3 entities:
Payment Transactions:
#Entity
#Table(name = "payment_transactions")
public class PaymentTransactions implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private int id;
.....
}
WPF Payments:
#Entity
#Table(name = "wpf_payments")
public class WpfPayments implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private int id;
............
}
WPF Payments Payment transactions:
#Entity
#Table(name = "wpf_payment_payment_transactions")
public class WpfPaymentPaymentTransactions implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false, length = 3)
private int id;
#Column(length = 4)
private Integer wpf_payment_id;
#Column(length = 4)
private Integer payment_transaction_id;
.....
}
I use these SQL requests to get proper data based in id:
SELECT `payment_transactions`.* FROM `payment_transactions` INNER JOIN `wpf_payment_payment_transactions` ON `payment_transactions`.`id` = `wpf_payment_payment_transactions`.`payment_transaction_id` WHERE `wpf_payment_payment_transactions`.`wpf_payment_id` = 75 ORDER BY `payment_transactions`.`id` ASC LIMIT 1
SELECT `payment_transactions`.* FROM `payment_transactions` INNER JOIN `wpf_payment_payment_transactions` ON `payment_transactions`.`id` = `wpf_payment_payment_transactions`.`payment_transaction_id` WHERE `wpf_payment_payment_transactions`.`wpf_payment_id` = 75
Is there some way to implement these SQL requests using JPA queries?
If you are using JPA 2.0, it is not possible to use JPQL with your queries since you cannot use the ON clause.
One solution is to implement a Bidirectional Mapping on the entities WpfPaymentPaymentTransactions,
PaymentTransactions to be able to make a join :
#Entity
#Table(name = "payment_transactions")
public class PaymentTransactions implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false)
private int id;
#OneToOne(mappedBy="paymentTransactions") //or OneToMany depending on your model
private WpfPaymentPaymentTransactions wpfPaymentPaymentTransactions;
}
#Entity
#Table(name = "wpf_payment_payment_transactions")
public class WpfPaymentPaymentTransactions implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", unique = true, updatable = false, nullable = false, length = 3)
private int id;
#ManyToOne
#JoinColumn(name="wpf_payment_id")
private PaymentTransactions paymentTransactions;
}
Then you can join the two entities like this :
SELECT t FROM PaymentTransactions t
INNER JOIN WpfPaymentPaymentTransactions wppt
Starting from JPA 2.1, You can add the ON clause with JPQL query. So for the first query, it will be like this :
SELECT t FROM PaymentTransactions t
INNER JOIN WpfPaymentPaymentTransactions wppt
ON t.id = wppt.paymentTransactionId`
WHERE wppt.wpfPaymentId = :param
ORDER BY t.id ASC LIMIT 1
Hope it helps!
Related
I was creating my classes for a project using a chart for practice purposes until I stumbled upon this order_items:
I had no problem creating an Entity like Orders or Products because I knew that for Orders I just had to do something like:
#Entity
#Table(name = "orders")
public class Orders {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "order_id")
private Integer orderId;
// rest of the code...
}
And for for Products something like:
#Entity
#Table(name = "products")
public class Products {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "product_id")
private Integer productId;
// rest of the code...
}
But the table order_items has the variables order_id and item_id, does that count as a composite key? If that is the case, how should those variables look in my OrderItems class?
#Entity
#Table(name = "order_items")
public class OrderItems {
#Column(name = "order_id")
private Integer orderId;
#Column(name = "item_id")
private Integer itemId;
// rest of the code...
}
I've checked different questions and they mention using #IdClass or #EmbeddableId for composite keys, but I'd like to confirm first if that is what I should do in this situation, unless it's not the case, maybe there are more approaches.
I'd really appreciate opinions and/or any article related to this, thank your for your time.
As you mentioned you can use #EmbeddableId.
Here is example :
#Embeddable
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
public class OrderItemsPK implements Serializable {
private static final long serialVersionUID = 1L;
#Column(insertable = false, unique = false, updatable = false, nullable = false,name = "order_id")
private Long orderId;
#Column(insertable = false, unique = false, updatable = false, nullable = false,name = "products_id")
private Long productsId;
}
And the Order Items Class.
#Entity
public class OrderItems {
#EmbeddedId
private OrderItemsPK id;
#OneToOne
#JoinColumn(name = "products_id", nullable = false, unique = false, insertable = false, updatable = false, referencedColumnName = "products_id")
private Products products;
#OneToOne
#JoinColumn(name = "orders_id", nullable = false, unique = false, insertable = false, updatable = false, referencedColumnName = "orders_id")
private Order order;
private Long itemId;
}
I have table performance and hours. One performnace can be played many times at certain hours. One to Many relations.
#Entity
#Table(name = "performance_type")
#Data
public class PerformanceType {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, unique = true)
private Integer performanceTypeId;
#Column(length=127)
private String performOptions;
}
and
#Entity
#Table(name = "performance")
#Data
public class Performance {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, unique = true)
private Integer performanceId;
#OneToMany(mappedBy = "performance")
private List<Hours> performanceHours = new ArrayList<>();
}
In database hibernate create table hours that have performanceId thas have only one value. How i may insert list values that performance with id 1,4,7 are played in the same time. That i need additoinal table hours_performance that store hourId and perfomanceId?
Since the relationship you want to achieve is (according to my understanding) many-to-many, you do indeed need a third table mapping hours to relationships. Here is a very good example. You will need to set up your third table with two foreign keys to the two tables you want to connect.
#Entity
#Table(name = "performance")
#Data
public class Performance {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, unique = true)
private Integer performanceId;
#ManyToMany
#JoinTable(
name = "hours_performance",
joinColumns = { #JoinColumn(name = "performance_id") },
inverseJoinColumns = { #JoinColumn(name = "hour_id") }
)
private List<Hours> performanceHours = new ArrayList<>();
}
#Entity
#Table(name = "hours")
#Data
public class Hours {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, unique = true)
private Integer hourId;
ZonedDateTime time;
#ManyToMany(mappedBy = "performanceHours")
private List<Performance> performances;
}
I have two entities
Entity 1
#Entity
#Table(name = "Table1")
public class Table1{
#Id
#SequenceGenerator(name = "Table1_SEQ", sequenceName = "Table1_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Table1_SEQ")
#Column(name = "seq", updatable = false, unique = true, insertable = true)
private Long seq;
#Column(name = "number", updatable = false, insertable = true)
private Long number;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "enumber", updatable = false, insertable = true)
private Table2 table2;
Entity 2
#Entity
#Table(name = "Table2")
public class Table2 {
#Id
#SequenceGenerator(name = "Table2_SEQ", sequenceName = "Table2_SEQ", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "Table2_SEQ")
#Column(name = "enumber")
private Long eNumber;
I have a repository which extends JpaRepository
public interface Table1Repository extends JpaRepository<Table1, Long> {
}
When I try to save using
Table1Repository rep;
Table1 table1; // Assume this is initialized correctly
rep.save(table1);
I get a Foriegn Key constraint error org.springframework.dao.DataIntegrityViolationException
Table1 has a Foreign Key association with Table2 on the column enumber but I don't want to insert anything into Table2.
How do I save into Table1?
I'm not too familiar with Jpa so please let me know if you need any clarifications on what I'm asking or if you need any more information.
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "enumber", updatable = false, insertable = true)
private Table2 table2; // THIS IS WRONG!
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "enumber", updatable = false, insertable = true)
private Long enumberFKTable2; // THIS IS CORRECT!
//getters and setters
Implement another java class similar to table1 called table2 with all the spring annotations. Then you do the following code:
//First, make sure that the foreign key exists!
number enumber = entityManager.getReference(Enumber.class, enumberId);
//test
if(enumber != null){
Table 1 table1 = new Table1();
table1.setEnumber(enumber);
entityManager.persist(table1);
}
I use hibernate and spring-data. There are two tables with many-to-many relationship.
#Entity
#Table(name = "FirstEntity")
public class FirstEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_entity_id")
private Long id;
#Column(name = "first_entiry_name")
private String name;
/* getters and setters are below*/
}
#Entity
#Table(name = "SecondEntity")
public class SecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "second_entity_id")
private Long id;
#Column(name = "second_entiry_name")
private String name;
#Column(name = "second_entiry_desc")
private String description;
/* getters and setters are below*/
}
And entity for cross-reference table.
#Entity
#Table(name = "FirstSecondEntity")
public class FirstSecondEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "first_second_entity_id")
private Long id;
#Column(name = "first_entity_id")
private Long firstEntityId;
#Column(name = "second_entity_id")
private Long secondEntityId;
/* getters and setters are below*/
}
I need SELECT like this
SELECT FirstEntity.name, SecondEntity.name, SecondEntity.description FROM SecondEntity INNER JOIN FirstSecondEntity ON SecondEntity.id = FirstSecondEntity.secondEntityId INNER JOIN User ON FirstEntity.id = FirstSecondEntity.firstEntityId
i.e. I need all records from cross-reference table where instead of ids there is actual info from entities.
Inserting this query into #Query annotation in my CrudRepository-extended class doesn't work because of
ERROR [main][org.hibernate.hql.internal.ast.ErrorCounter] Path expected for join!
So I need your help.
Your join table is all screwed up. In this case, you actually don't even need the join table as a hibernate mapping:
In Second Entity add the following list:
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "FirstSecondEntity",
joinColumns = {
#JoinColumn(name = "first_entity_id",
nullable = false,
updatable = false) },
inverseJoinColumns = {
#JoinColumn(name = "second_entity_id",
nullable = false,
updatable = false) },
)
private List<FirstEntity> firstEntities;
In FirstEntity add the following list:
#ManyToMany(fetch = FetchType.LAZY,
mappedBy = "firstEntities")
private List<SecondEntity> secondEntities;
I am trying to create a ManyToMany relation between DocumentModels, with an additionnal information in the relation (dosIndex)
#Entity
#Table(name = "T_DOCUMENT_MODELS_DMO")
public class TDocumentModelsDmo extends fr.axigate.nx.frontend.server.common.entity.ValidityPeriodEntity implements Serializable
{
#Id
#SequenceGenerator(name = "T_DOCUMENT_MODELS_DMO_DMOID_GENERATOR", sequenceName = "T_DMO_ID_SEQ")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "T_DOCUMENT_MODELS_DMO_DMOID_GENERATOR")
#Column(name = "DMO_ID", precision = 22)
private Long dmoId;
//Other unrelated members, no reference to TjDocumentSourcesDos
//constructors, getters and setters without annotations
}
#Entity
#Table(name = "TJ_DOCUMENT_SOURCES_DOS")
public class TjDocumentSourcesDos implements Serializable
{
#Column(name = "DOS_INDEX", nullable = false, precision = 22)
private long dosIndex; //the additionnal info on the relation
#EmbeddedId
private TjDocumentSourcesDosPK id = new TjDocumentSourcesDosPK();
#ManyToOne
#MapsId("dosParentId")
#JoinColumn(name = "DOS_PARENT_ID", nullable = false, insertable = false, updatable = false)
private TDocumentModelsDmo TDocumentModelsDmoParent;
#ManyToOne
#MapsId("dosSourceId")
#JoinColumn(name = "DOS_SOURCE_ID", nullable = false, insertable = false, updatable = false)
private TDocumentModelsDmo TDocumentModelsDmoSource;
//constructors, getters and setters without annotations
}
#Embeddable
public class TjDocumentSourcesDosPK implements Serializable
{
#Column(name = "DOS_PARENT_ID", nullable = false, precision = 22)
private Long dosParentId;
#Column(name = "DOS_SOURCE_ID", nullable = false, precision = 22)
private Long dosSourceId;
//constructors, getters and setters without annotations
//hashCode and equals implemented
}
I can insert datas in both tables, but when I try to request it using an entityManager, i get something strange :
Query query = entityManager.createQuery("SELECT dos.TDocumentModelsDmoSource FROM TDocumentModelsDmo AS dmo, TjDocumentSourcesDos as dos WHERE dmo.dmoId = :modelId AND dos.TDocumentModelsDmoParent = dmo");
query.setParameter("modelId", someData);
ArrayList<TjDocumentSourcesDos> dosList = (ArrayList<TjDocumentSourcesDos>) query.getResultList();
will work, while the following will throw an exception : QuerySyntaxException: dos.TDocumentModelsDmoSource is not mapped
Query query = entityManager.createQuery("SELECT sources FROM TDocumentModelsDmo AS dmo, TjDocumentSourcesDos as dos, dos.TDocumentModelsDmoSource AS sources WHERE dmo.dmoId = :modelId AND dos.TDocumentModelsDmoParent = dmo");
query.setParameter("modelId", someData);
ArrayList<TjDocumentSourcesDos> dosList = (ArrayList<TjDocumentSourcesDos>) query.getResultList();
This prevents me from doing more complicated requests where I would use my sources models in the WHERE condition.
I tried adding a referencedColumnName = "DMO_ID" in both my JoinColumn annotations, but I still get the same error