JPA avoid loading Objects before Insert - java

Person has a foreign key of the field "Language". How can I avoid loading the whole "Language" object if I just got the PK of a language ("json.get("language").asInt()) and want to insert a new Person?
#Entity
public class Person {
String prename;
String lastname;
Language language;
}
Person p = new Person("Robert", "Meyer");
Language l = JPA.em().find(Language.class, json.get("language").asInt();
p.setLanguage(l);
Is it possible to do it in a way without having to load the whole Language object?

You could use EntityManager#getReference().
Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed.
Person p = new Person("Robert", "Meyer");
Language l = JPA.em().getReference(Language.class, json.get("language").asInt();
p.setLanguage(l);

Related

Object with null properties by QBean mapping on left joining table / Querydsl

I'm using Querydsl 4.1.0 to generate my Qtable from database, and also by myself, create the Qbean for transforming result into my Java object. The problem I'm facing is, my A class has a B class property , and if I use ' A left join B', then if there's no existed B for A's id in database (which will result in null values of those columns from B table on that row), my A object after transformation will have a B object, with all null properties. Is there anyway to avoid this undesired B object to be instantiated?
I can see that the problem here is newInstance() method of QBean always create a B instance and return it regardless of the fact all field's values is null, which is not so right in my opinion.
My classes :
protected final QBean<Contact> contactQBean =
Projection.fields(Contact.class,
qContact.id, qContact.firstName, qContact.lastName,
qContact.middleName, addressQBean.as("primaryAddress"));
------------------------
public class Contact {
private Integer id;
private String firstName;
private String middleName;
private String lastName;
private Address primaryAddress;
My query :
Map<Integer, Contact> resultMap = queryFactory.from(qContact)
.leftJoin(qContact.contactAddressFK, qAddress)
.transform(groupBy(qContact.id).as(contactQBean));
Your question is too difficult and complex. I do not know the answer. But maybe you can try to go to your IDE and copy some other codes from stack.
Hope it helps

Hibernate calculated collection #Formula

is it possible to have and Entity with a field calculated using Formula when the field is a Collection (let's say it's a Set)?
Here's the dummy example of what I'm trying to achive:
#Formula(value =
"SELECT NEW com.example.entity.Person(p.name, p.age) FROM Person p")
lateinit var people :Set<Person>
From the JavaDoc for #Formula:
Defines a formula (derived value) which is a SQL fragment ...
You have to think of the fragment you write as an replacement in the select statement:
SELECT (formulaValue) AS propertyName FROM ....
Everything you can write into formulaValue can be used in #Formula.
Your example is not a valid SQL fragment and as you can see, it is not possible to return more than one value from a #Formula.
But you could use #Subselect and a wrapper object instead:
#Entity
#Subselect("SELECT name, age FROM Person p")
public class PersonWrapper {
#Id
private String name;
private int age;
}
(in Java, as I'm not aware of the correct syntax of Kotlin)
If you really need the collection of these values in another entity, you need something to join on (which is missing in your example) and use that in an #OneToMany or #ManyToMany. Otherwise there is no use to have all these values in your entity, as all entities would have the same collection.

How to code query from SQL in Java for object oriented metamodel

I'm trying to learn how to create an object oriented model database using a tool called: Eyedb (on linux). I've made some classes and records generators for this database but I don't know how to code queries for it using Java.
The structure of the database looks like this:
class Lecturer {
attribute string<32> name;
attribute strin<32> surname;
relationship set <Lecture*> lectures inverse Lecture::Lecturer;
};
class Item{
attribute string<32> name;
attribute string<512> description;
};
class Topic extends Item {
relationship set<Lecture*> tlecture inverse Lecture::Topic;
};
class Lecture {
relationship Lecturer *llecturer inverse Lecturer::lectures;
relationship Topic *ltopic inverse Topic::tlecture;
relationship set <Content*> lcontent inverse Content::Lecture;
relationship set <Equipment*> lequipment inverse Content::Lecture;
relationship Room_timeslot* lroom_timeslot inverse Room_timeslot::rlecture;
};
class Content extends Item {
attribute int level;
relationship set <Content*> subcontent inverse Content::supcontent;
relationship set <Content*> supcontent inverse Content::subcontent;
relationship set <Teachingmaterial*> cteachingmaterial inverse Teachingmaterial::Content;
};
class Teachingmaterial extends Item {
attribute string link;
relationship set <Content*> tcontent inverse Content::Teachingmaterial;
};
class Equipment extends Item {
attribute int quantity;
attribute string symbol;
relationship set<Lecture*> electure inverse Lecture::Equipment;
relationship Room *eroom inverse Room::requipment;
};
class Room {
relationship set <Equipment*> requipment inverse Equipment::Room
attribute string name;
attribute int number;
attribute string symbol;
attribute string building;
attribute int floor;
attribute string wing;
relationship set <Room_timeslot*> rroom_timeslot inverse Room_timeslot::Room;
};
class Room_timeslot {
relationship Room *room inverse room::rroom_timeslot;
relationship Lecture* rlecture inverse Lecture::Room_timeslot;
relationship set <Timeslot*> rtimeslot inverse Timeslot::lroom_timeslot;
};
class Timeslot {
attribute string name;
attribute int number;
attribute time timemargin_start;
attribute time timemargin_end;
relationship set <Room_timeslot*> troom_timeslot inverse Room_timeslot::rtimeslot;
};
I want to make queries that look like this:
SELECT lr.name as lecturer, t.name as topic FROM topic t
JOIN lecture l ON t.id_topic = l.id_topic
JOIN lecturer lr ON lr.id_lecturer = l.id_lecturer
ORDER BY lr.name
select t.name as topic from topic t
join lecture l on t.id_topic = l.id_topic
join lecturer lr on lr.id_lecturer = l.id_lecturer
where lr.name = "name1"
SELECT tm.name as teaching_material, e.name as equipment, lr.name as lecturer FROM teachingmaterial tm
JOIN teaching_content tc ON tc.id_teachingmaterial = tm.id_teachingmaterial
JOIN content c ON c.id_content = tc.id_content
JOIN content_lecture cl ON cl.id_content = c.id_content
JOIN lecture l ON l.id_lecture = cl.id_lecture
JOIN lecture_equipment le ON le.id_lecture = l.id_lecture
JOIN equipment e ON e.id_equipment = le.id_equipment
JOIN lecturer lr ON lr.id_lecturer = l.id_lecturer
Java uses JDBC to communicate with a relational database. If your database has a JDBC driver you're all set. If not, you're out of luck. Both SQL Server and MySQL have JDBC drivers, so they should not be a problem. You'll need those and the JDBC tutorial.
Looks like EyeDB is an object database that I've never heard of. It claims to be usable by C++ and Java.
I'd expect at least one "hello world" connection example. I'm suspicious of any software that doesn't even get the HTML on its web page right.
There's Java documentation available. Looks awful. Is this a requirement? There are better databases, both relational (MySQL, SQLLite, or PostgreSQL), object (e.g. JODB), or graph (NEO4J). Must you use this one?
The EyeDB documentation makes the steps clear. They are spelled out for you in the sample problem:
Define the schema using the EyeDB Object Definition Language (ODL)
Generate the Java classes from the schema using the EyeDB eyedbodl tool, which comes with your download.
Write a client program using the generated classes that interact with the database.
It's all there. Give it a try.

How to get key generated by Hibernate when I map a collection with #collectionId?

I am working on Quiz management. All mapping is done by Hibernate annotation for question to options. Question is an entity whereas all options are embedded object so I mapped option as follows :
QuestionMasterDTO's mapping for TabkidsMCQOptionMasterDTO :
#ElementCollection(fetch=FetchType.EAGER,targetClass=TabkidsMCQOptionMasterDTO.class)
#Fetch(FetchMode.SUBSELECT)
#Cascade(org.hibernate.annotations.CascadeType.ALL)
#CollectionTable(name="TABKIDS_MCQ_OPTION_MASTER",joinColumns={#JoinColumn(name="TMOM_QUESTION_ID")})
#GenericGenerator(name="hilo-gen",strategy="hilo")
#CollectionId(columns={#Column(name="TMOM_ID")},generator="hilo-gen", type=#Type(type="long"))
public Collection<IOptionMaster> getOptions() {
return options;
}
Where TabkidsMCQOptionMasterDTO is :
#Embeddable
public class TabkidsMCQOptionMasterDTO implements IOptionMaster {
private String optionText;
private boolean correct;
#Column(name = "TMOM_OPTION_TEXT")
public String getOptionText() {
return optionText;
}
#Column(name = "TMOM_IS_CORRECT")
public boolean isCorrect() {
return correct;
}
//setters omitted
}
Now in above mapping you can see I am using a generator i.e. hilo-gen and assigning a unique id to every option available in collection and that column name is 'TMOM_ID'.
This line :
#GenericGenerator(name="hilo-gen",strategy="hilo")
#CollectionId(columns={#Column(name="TMOM_ID")},generator="hilo-gen", type=#Type(type="long"))
Now when I fetch a question from database by using Hibernate criteria I am getting all options associated with the question but not getting unique option id i.e. TMOM_ID. How to get this id ??
Hibernate mainly uses two type of mapping Entity Type and Value Type.
Entity type means It will have its own existence in the world i.e. It must have a primary key.
Whereas Value type don't have its own existence this means value type always dependent on Entity type.
As your problem I can see Option does not have its won existence because it must always dependent of Question which is an entity .
So from my point of view if you want to access Option Id, Option must also be an entity type this means You have to use #Entity on top of TabkidsMCQOptionMasterDTO rather than making it as #Embeddable.
So here you have to use #OneToMany in your question master and from Other side in TabkidsMCQOptionMasterDTO you have to use #ManyToOne mapping.
I hope this will help to achieve what you want to get.

JPA : Is there any way to run a simple SELECT statement that only access a few columns?

I'm new to JPA so forgive me if my question seems silly.
We have used JPA in our project. I see that every entity object has a direct mapping with a table and each row in the table is an object of that entity type.
But, suppose I only want to access one or two columns of a table, how do i go about doing it ? The reason I'm asking is because of the task i have in hand.
There are two tables. The first table has everything set up with JPA so that each row can be cast into an object type. The first table has a column that is referenced in the second table i.e. say, table A has column CLOTH_ID and Table B has columns CLOTH_ID and CLOTH_DESCRIPTION. CLOTH_ID is used in both Table A and B; But B has the CLOTH_DESCRIPTION columns which corresponds to CLOTH_ID.
I'm displaying Table A in my webpage but I also need to display : CLOTH_DESCRIPTION in my webpage. Is there a JPA oriented way to do this or Am i better off using regular JDBC to extract the CLOTH DESCRIPTION values ?
I assume you have the following setup:
#Entity
#Table(name="A")
class A {
#ManyToOne
#JoinColumn(name="CLOTH_ID")
private B cloth;
//...
}
#Entity
#Table(name="B")
class B {
#Id
#Column(name="CLOTH_ID")
private int id;
#Column(name="CLOTH_DESCRIPTION")
private String description;
//...
}
If you don't... you're doing it wrong (i.e. it is not idiomatic JPA usage). You have the following options:
Simply fetch A
In this case #ManyToOne relationship will be fetched eagerly by default as well. Then simply call in Java:
a.getCloth().getDescription()
Prefer this approach as it is the simplest and most idiomatic unless the number of columns in B is huge.
Use JPA query with custom columns:
SELECT a, a.b.description
FROM A a
WHERE a.id = :id
In this case the query returns List<Object[]>, where Object[] actually contains two elements: A and String.
Same as above but with custom DTO:
class Adto {
private final A a;
private final String description;
public Adto(A a, String description) {
this.a = a;
this.description = description;
}
}
And slightly modified query:
SELECT new Adto(a, a.b.description)
FROM A a
WHERE a.id = :id

Categories

Resources