Spring JPA Formula with multiple columns - java

I am trying to read data from another table based on the value of one of the fields in the current entity. But somehow I am facing an issue selecting multiple fields inside the formula.
#Entity
#Table(name = "contacts")
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class ContactInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "url")
private String imageUrl;
//Not working
#Formula("(select code,area from areas where area_id=id)")
private Map<String, String> vals;
//working
#Formula("(select code from areas where area_id=id)")
private String someVal;
}
is there any way that I can use the formula for retrieving multiple columns of data with multiple rows?
Thanks for your help.

I'm not sure you can retrieve like Map<string, String>. Suppose you declare another field how you going to retrieve. you can receive as a List instead of Map<st..., str..>.
Instead of #Formulae, you can use #OneToMany & #ManyToOne. through a Bi-direction connection, you achieve your scenario.

This looks more like it should be using JPA's ElementCollection mapping to the Area table, with a MapKeyColumn mapping:
public class ContactInfo {
..
#ElementCollection
#MapKeyColumn(name="code")//key
#Column(name="area") //value
#CollectionTable(name="areas",
joinColumns=#JoinColumn(name="area_id"))//fk from Areas->contacts.id
private Map<String, String> vals;
..
See this for some more information and examples.

Related

Is this relationship a #OneToMany instance?

I already have two tables:
zip_codes_germany
and
travel_agencies
filled with some data. Where travel_agencies has a composite key from columns name and city and zip_codes_germany has the primary key zip_code.
Let the condition be fulfilled that the city names are the same in both tables. Now one city maps to multiple zip_codes.
What is the best way to make this relationship clear in order to receive the correct list of zip codes when loading a TravelAgency object using hibernate?
I'm thinking of something like this:
#Entity
#Table(name = "travel_agencies")
public class TravelAgency implements Serializable {
private static final long serialVersionUID = -5215122407119218666L;
#Id
#Column(name = "name")
private String name;
#Id
#Column(name = "city")
private String city;
#Column(name = "ceo")
private String ceo;
#OneToMany
#JoinColumn(name = "city")
private Set<ZipCodeArea> zipCodeAreas;
I'm new to hibernate and working with databases in general so I'm not quite sure if it is the correct tool to get what I'm asking for or if I'd better go with something else?
As commented by OH GOD SPIDERS, I do have a many to many relationship here.

Spring Data/Hibernate Generates two queries instead of a JOIN

Context: I have two tables: Questionnaire and Question Section. A Questionnaire can have many Question Sections. Questionnaires and Question Sections both have Start and End Dates to determine if they are active records.
Here are my entities as written:
#Entity
#Data
public class Questionnaire {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
private String name;
private Date startDate;
private Date endDate;
private String description;
#OneToMany(cascade = CascadeType.All,
fetch = FetchType.LAZY,
mappedBy = "questionnaire")
#JsonManagedReference
private List<QuestionSection> questionSections = new ArrayList<QuestionSection>();
}
#Entity
#Data
public class QuestionSection {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
private String name;
private String description;
private int sectionLevel;
private Date startDate;
private Date endDate;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "QUESTIONNAIRE_ID", nullable = false)
#JsonBackReference
private Questionnaire questionnaire;
}
Here is my Spring Data Repository with a single declared method:
public interface QuestionnaireRepository extends JpaRepository<Questionnaire, UUID> {
Questionnaire findByNameAndEndDateIsNull(String name);
// Previous goal query, but worked all the way back to the above simple query
// Questionnaire findByIdAndQuestionSectionsEndDateIsNull(UUID id);
}
The above derived query generates two queries shown below:
-- For brevity
select questionnaire.id as id
questionnaire.description as description
questionnaire.end_date as end_date
questionnaire.start_date as start_date
from questionnaire
where questionnaire.name='Foo' and (questionnaire.end_date is null)
select questionsection.questionnaire_id as questionnaire id
...rest of fields here...
from question_section
where questionsection.questionnaire_id = id from above query
Then Spring Data or Hibernate is combining those two above queries into one data object representative of the questionnaire object and returning that.
My problem with this is that I would have expected One query to run with a Join between the two tables, not two and then combine the results in memory. I'm pretty experienced with Spring Data and ORMs in general and have not been able to find any documentation as to why this is happening. Honestly I wouldn't care except that my original intention was to query at the parent entity and 'filter' out children that have end dates (not active). This derived query (commented out above) exhibited the same behavior which ultimately resulted in the data set that was returned containing the end dated question sections.
I know there's 100 other ways I could solve this problem (which is fine) so this is more of an educational interest for me at this point if anyone has any insight into this behavior. I could be missing something really simple.
You should be able to do this using the Entity Graph feature introduced in JPA 2.1.
https://www.baeldung.com/jpa-entity-graph
Spring Data offers support for Entity Graphs via the #NamedEntityGraph and #EntityGraph annotations:
https://www.baeldung.com/spring-data-jpa-named-entity-graphs
So in your code:
Entity:
#Entity
#NamedEntityGraph(name = "Questionnaire.questionSections",
attributeNodes = #NamedAttributeNode("questionSections ")
)
public class Questionnaire{
//...
}
Repository:
public interface QuestionnaireRepository extends JpaRepository<Questionnaire, UUID> {
#NamedEntityGraph("Questionnaire.questionSections")
Questionnaire findByNameAndEndDateIsNull(String name);
}
public interface QuestionnaireRepository extends JpaRepository<Questionnaire, UUID> {
#EntityGraph(attributePaths = { "questionSections" })
Questionnaire findByNameAndEndDateIsNull(String name);
}

Hibernate - Many to One relationship, possibility to delete last shared reference automatically?

I have a many-to-one relationship and I like that the last shared reference should get deleted by hibernate automatically. The questions are
is this is supported by hibernate?
if not can I achieve this by adding some kind of api callbacks from JPA/Hibernate rather then fully code it in the DAOs by myself?
Example I have an "Attribute" (Name/Value Pair) which is an entity and its shares some "Translation" for its name with other Attributes. So if an attribute get deleted hibernate should check if still another attribute exists where the same translation is used. If there is no one left the translation should be deleted as well.
#Entity
public class Attribute {
#Id
#GeneratedValue
private int id;
private String name;
#Lob
private String value;
#ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
#JoinColumn(name="name_translation_id")
private Translation nameTranslation;
...
}
#Entity
public class Translation {
#Id
#GeneratedValue
private int id;
#ElementCollection (fetch=FetchType.LAZY)
#CollectionTable(name= "translation_values", joinColumns = #JoinColumn(name = "translation_id"))
#MapKeyColumn(name="language_code")
#Column(name = "value")
#Lob
private Map<String, String> values = new HashMap<String, String>();
...
}
I am using hibernate v4.3.
I think Jpa Entity Listeners good choice for you
for your question write one metod and anotate #PostRemove in Attribute.class
#PostRemove
public void removeTranslationByAttribute(Attribute attribute){
List<Attribute> attributes = AttributeRepository.getByNameTranslationId(attribute.getNameTranslation()); //get all atribute by `name_translation_id`
if(attributes.size() == 0) // when not include atrribute in list`name_translation_id`
TranslationRepository.deleteById(attribute.getNameTranslation()); // delete translation object by `name_translation_id`
}

JPA: Foreign key that is also a primary key mapping

I have been trying to solve this for whole day but no luck! Also i tried to read most of the tutorials on the net but as you all know they all are full of useless examples that do not reflect what you need in the real world.
So here is my situation:
The database:
table: vehicles(vehicleId, brand, model, devYear, regNumber) <-- vehicleId is the PrimaryKey
table: extras(vehicleId, allowSmoke, allowFood, allowDrinks, airConditioner) <-- vehicleId is a PK and a FK.
The point is that if i have a class Vehicle and a class TravelExtras which are mapped to the database i want the Vehicle class to have an attribute TravelExtras travelExtras and get and set methods.
Unfortunatelly no matter what i tried when i try to persist the object in the databse i get various errors.
Here is an illustration:
EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "NaStopPU" );
EntityManager entitymanager = emfactory.createEntityManager( );
entitymanager.getTransaction( ).begin( );
TravelExtra travelExtra = new TravelExtra();
entitymanager.persist(travelExtra);
Vehicle vehicle = new Vehicle(2L, "10152487958556242", "Mazda", "626", "334343", 2005, 4);
vehicle.setTravelExtra(travelExtra);
entitymanager.persist(vehicle);
entitymanager.getTransaction().commit();
entitymanager.close( );
emfactory.close( );
Any one knows what kind of annotations to use for this One to one case ?
The Java Persistence wikibook has a section called Primary Keys through OneToOne and ManyToOne Relationships which seems to indicate that what you want is possible.
If I'm reading it right, for your case, it would look something like:
class Vehicle {
#Id
#Column(name = "EXTRAS_ID")
private long extrasId;
#OneToOne(mappedBy="vehicle", cascade=CascadeType.ALL)
private TravelExtra extras;
}
class TravelExtras {
#Id
#Column(name = "VEHICLE_ID")
private long vehicleId;
#OneToOne
#PrimaryKeyJoinColumn(name="VEHICLE_ID", referencedColumnName="EXTRAS_ID")
private Vehicle vehicle;
public TravelExtras(Vehicle vehicle) {
this.vehicleId = vehicle.getId();
this.vehicle = vehicle;
}
}
Note that one of your entities will need to make sure it has the same id as the other, which is accomplished in the example by the TravelExtras constructor requiring the Vehicle it is bound to.
I know this is very old qs, but for completeness of your case
you can just have (jpa 2.0)
#Entity
#Data
public class Vehicle implements Serializable{
#Id
#GeneratedValue
private long vehicleId;
.. //other props
}
#Entity
#Data
public class VehicleExtras implements Serializable{
#Id
#OneToOne (cascade = CASCADE.ALL)
#MapsId
#JoinColumn(name ="vehicleId")
private Vehicle vehicle;
#Column
private boolean allowSmoke;
..// other props.
}
should share same pk/fk for VehicleExtra table
Why don't you use an #Embedded object? When using an embedded object, you get
the logical separation you desire in your code and keep your database compliant with Entity-Relational Normalization rules.
It's weird to think on a One-to-One relationship, because even though JPA/Hibernate allows it, all data should be stored in the same table, making you model simpler, while also simplifying queries and increasing database performance by removing the need for a Join operation.
When using Embedded objects you don't have to worry about mapping IDs and bizarre relations, since your ORM is capable of understanding that your just making a code separation, instead of demanding an actual relation of One-to-One between tables.
class Vehicle {
#Id
#Column(name = "ID")
private long vehicleId;
#Column(name = "BRAND")
private String brand;
#Column(name = "MODEL")
private String model;
#Column(name = "DEV_YEAR")
private int devYear;
#Column(name = "REG_NUMBER")
private int regNumber;
#Embedded
private TravelExtra extras;
// Constructor, getters and setters...
}
.
#Embeddable
class TravelExtras {
#Column(name = "ALLOW_SMOKE")
private boolean allowSmoke;
#Column(name = "ALLOW_FOOD")
private boolean allowFood;
#Column(name = "ALLOW_DRINKS")
private boolean allowDrinks;
#Column(name = "AIR_CONDITIONER")
private boolean airConditioner;
// Default Constructor, getters and setters...
}
You can map your classes for example with Netbeans. It will generate annotations. The problem could be your dao layer. You have to persist objects in correct way. For example can't save travelExtra without Vehicle. Also be aware of owning side.

Joining two table in spring data JPA and Querying two table data from repository

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

Categories