I am using Play framework with Ebean. I have two models, below are the code:
public class User extends Model {
#Id
public Long id;
public String name;
/* rest of attributes */
public static Finder<Long,User> find = new Finder<Long,User>(
Long.class, User.class
);
}
public class Admin extends Model {
#Id
public Long id;
#OneToOne
public User user;
/* rest of attributes */
public static Finder<Long,Admin> find = new Finder<Long,Admin>(
Long.class, Admin.class
);
}
When I do Logger.info(admin.user.name) in Java, I can see the name of the admin. But when I pass the Java object to Scala using view render, if I do #admin.user.id, I can still get the id, but if I do #admin.user.name, I get nothing (with no error). I'm just wonder how can I access the name attribute from a joined table?
Problem solved.
Before when I do the fetching, I did
Admin.find.where()
.ilike("user.name", "%" + filter + "%")
.orderBy("user."+sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);
After changing to
Admin.find.fetch("user", new FetchConfig().query())
.where()
.ilike("user.name", "%" + filter + "%")
.orderBy("user."+sortBy + " " + order)
.findPagingList(pageSize)
.getPage(page);
It successfully displayed instance variables on Scala.
Related
I'm new to Spring boot and I'm writing an application to practice, with Postresql as db.
The application is about aviation. There are 4 entity: Airline, Airplane, Airport and Flight.
I tried GET, POST and DELETE requests and all works on Airline, Airplane and Airport, but I have a problem trying to add and update Flight.
Flight has 4 ManyToOne relationships, this is the class:
#Entity
#Table
public class Flight {
#Id
#Column(name = "flight_number")
private String flightNumber;
#ManyToOne
#JoinColumn(name = "origin")
private Airport origin;
#ManyToOne
#JoinColumn(name = "destination")
private Airport destination;
#Column(name = "departure_time")
private Timestamp departureTime;
#Column(name = "arrival_time")
private Timestamp arrivalTime;
#ManyToOne
#JoinColumn(name = "airline")
private Airline airline;
#ManyToOne
#JoinColumn(name = "airplane")
private Airplane airplane;
private Time duration;
private int passengers;
...
}
What I don't understand is how to insert and update this entity without the need to pass the Objects (Airline and Airport) but only the foreign keys (as when working directly on db).
Here is my code for add a new flight that requires the objects:
public void addFlight(Flight flight) {
boolean exists = flightRepository.existsById(flight.getFlightNumber());
if (exists) {
throw new IllegalStateException("Flight with number" + flight.getFlightNumber()
+ "already exists");
}
flightRepository.save(flight);
}
I also tried writing a specific query for the update in the repository and then call on PUT request, but I get some errors saying that I need to pass Airline and Airport, not strings that represents the IDs of these 2 entities.
*#Modifying
#Query("update Flight " +
"set origin = :origin, " +
"destination = :destination, " +
"departureTime = :departureTime, " +
"arrivalTime = :arrivalTime, " +
"airline = :airline, " +
"airplane = :airplane, " +
"passengers = :passengers, " +
"duration = :duration " +
"where flightNumber = :flightNumber")
void updateFlight(#Param("flightNumber") String flightNumber,
#Param("origin") String origin,
#Param("destination") String destination,
#Param("departureTime") Timestamp departureTime,
#Param("arrivalTime") Timestamp arrivalTime,
#Param("airline") String airline,
#Param("airplane") Long airplane,
#Param("passengers") Integer passengers,
#Param("duration") Time duration);*/
To summarize: I want to know if there is a method to avoid passing the entire Object that represents the ManyToOne relationship during creation and update.
Is the method addFlight(Flight flight) called from your controller? If that's the case, you should get a DTO from your controller that you'll map in an entity in your service layer.
From the DTO you'll need to provide the ids of Airline, Airplane and Airport objects so that you can retrieve them from the DB and set them on the Flight entity.
Here is a solution I can suggest:
void addFlight (FlightRequest flightRequest) {
boolean exists = flightRepository.existsById(flightRequest.flightNumber());
if (exists) {
throw new IllegalStateException("Flight with number" + flight.getFlightNumber()
+ "already exists");
}
Flight flight = new Flight();
airportRepository.findById(flightRequest.airportOriginId())
.ifPresentOrElse(airportOrigin -> {
flight.setAirportOrigin(airportOrigin);
},
() -> new IllegalStateException(...)
);
airportRepository.findById(flightRequest.airportDestinationId())
.ifPresentOrElse(airportDestination -> {
flight.setAirportDestination(airportDestination);
},
() -> new IllegalStateException(...)
);
airlineRepository.findById(flightRequest.airlineId())
.ifPresentOrElse(airline -> {
flight.setAirline(airline);
},
() -> new IllegalStateException(...)
);
airplaneRepository.findById(flightRequest.airplaneId())
.ifPresentOrElse(airplane -> {
flight.setAirplane(airplane);
},
() -> new IllegalStateException(...)
);
flight.setFlightNumber(flightRequest.flightNumber());
flight.setDepartureTime(flightRequest.departureTime());
flight.setArrivalTime(flightRequest.arrivalTime());
flight.setDuration(flightRequest.duration());
flight.setPassengers(flightRequest.passengers());
...
flightRepository.save(flight);
}
public record FlightRequest(
String flightNumber,
String airportOriginId,
String airportDestinationId,
Timestamp departureTime,
Timestamp arrivalTime,
String airlineId,
String airplaneId,
Time duration,
int passengers,
...
) {
}
And for updating your Flight, you could do it like this:
Flight updateFlight (FlightRequest flightRequest) {
Flight flight = flightRepository.findById(flightRequest.flightNumber())
.orElseThrow(...);
// Same as above without the call for existsById
...
}
If you want to go further, since version 2.7 of Spring Data JPA, you can use getReferenceById method instead of findById. In that case Spring Data JPA won't generate an SQL statement to get the entity, in our case we only want to set the foreign keys. You can find more about this here
I have following method which works fine however returns the objects in the alphabetical orders whenever being called from calling method :-
public List<Object> getExportDataFromView() {
try {
String selectQuery = "SELECT UNIQUE_ID, DATE, CODE, PRODUCT_CODE, "
+ " MESSAGE AS MESSAGE_TEXT, SOURCE, COMPANY_ID, REMARK, BATCH, COUNTRY, PRODUCT_CODE_SCHEME, EXTERNAL_TRANSACTION_ID, RETURN_CODE, CORRELATION_ID, BUSINESS_PROCESS, BATCH_EXPIRY_DATE "
+ " FROM \"test\".\"my-systems.Company::views.Export_Data_View\" "
+ " WHERE COMPANY_ID = 'C100' "
+ " ORDER BY DATE DESC";
Query q = this.em.createNativeQuery(selectQuery, ExportData.class);
return q.getResultList();
} catch (Exception e) {
return null;
} finally {
this.em.close();
}
}
Whenever this method is called from another calling method, the List returned is in sorted order (alphabetically). However, in the JPA Entity class of ExportData.java, the fields are declared in original order like below :-
#Entity
#Table(name = "\"my-systems.Company::views.Export_Data_View\"", schema="\"test\"")
public class ExportData implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String UNIQUE_ID;
private String CODE;
private String PRODUCT_CODE;
private String MESSAGE_TEXT;
private String SOURCE;
Is there any way to preserve the same order as declared in Entity class rather than being sorted without changing the return type i.e. List.
Any help would be highly appreciated.
Thank you
I'm trying to use JOOQ without code generation. I have a dao class that looks like this
public class FilesDao {
public List<FilePojo> getAllFiles() {
DataSource dataSource = DataSourceFactory.getTestiDataSource();
List<FilePojo> filePojos = new ArrayList<>();
try (Connection con = dataSource.getConnection()) {
DSLContext create = DSL.using(con, SQLDialect.MARIADB);
filePojos = create.select(field("tiedosto.id"), field("tiedosto.nimi"), field("tiedosto.koko_tavua"),
field("tiedosto.sisalto"), field("tiedosto.hlo_id"))
.from(table("tiedosto"))
.where(field("minioupload").eq((byte) 0))
.fetch().into(FilePojo.class);
} catch (SQLException e) {
e.printStackTrace();
}
return filePojos;
}
}
and a Pojo class that looks like this
import javax.persistence.Column;
import javax.persistence.Table;
#Table(name="tiedosto")
public class FilePojo {
#Column(name = "id")
private Integer id;
#Column(name = "hlo_id")
private Integer customerId;
#Column(name = "koko_tavua")
private Integer fileSize;
#Column(name = "nimi")
private String fileName;
#Column(name = "sisalto")
private byte[] content;}
//Getters setters omitted
When I try to read from the table using a main method like this
public class App {
public static void main(String[] args) {
FilesDao mydao = new FilesDao();
List<FilePojo> myList = mydao.getAllFiles();
for (FilePojo filePojo : myList) {
System.out.println("==========================================" + "\n" +
filePojo.getId() + " " +
filePojo.getCustomerId() + " " +
filePojo.getFileName() + " " +
filePojo.getFileSize() + " " +
filePojo.getContent() + " " +
"==========================================");
}
}
}
The output is as follows
I can see that the SQL query is running fine and listing all the matched rows, but pojo is returning null values. What am I doing wrong here? Can someone please point me to the right direction? I'd really appreciate any sort of help.
I'm undecided whether this is a bug or a feature. You're using the plain SQL templating API when you should probably be using the identifier building API. When you write
field("tiedosto.id")
Then, jOOQ (possibly erroneously) thinks that your column is named `tiedosto.id`, with a period in the name. When it should really be qualified as `tiedosto`.`id`. There are a few possible fixes:
Keep using the plain SQL templating API
But then, don't qualify the name:
field("id")
Use the identifier building API
field(name("tiedosto", "id"))
Use the code generator
This should always be your preferred option, of course.
I have one to many relationship(Model 1->N Field), I want find all model with their fields. but the model's fields is empty object.
#NodeEntity
public class Model {
#Id
private String id;
private String name;
#Relationship(type = "ModelField", direction = Relationship.OUTGOING)
private List<Field> fields = new ArrayList<Field>();
}
#NodeEntity
public class Field {
#Id
private String id;
private String name;
}
public interface ModelRepo extends Neo4jRepository<Model, String>{
}
public ModelRepo mr;
Iterable<Model> models = mr.findALl();
// the model's fields is empty
I just reconstructed your scenario basing on your correct code and it works fine. I assume by populating your data something went wrong. Because that piece of code is missing, I can’t point you to the concrete reason. To help you nevertheless, I outline my steps to retrieve your field nodes.
Adding a FieldRepo repository:
public interface FieldRepo extends Neo4jRepository<Field, String> {
}
Populating your scenario:
Model model = new Model("modelId1", "Model1");
Field field = new Field("fieldId1", "Field1");
model.getFields().add(field);
Field field2 = new Field("fieldId2", "Field2");
model.getFields().add(field2);
modelRepo.save(model);
fieldRepo.save(field);
fieldRepo.save(field2);
Retrieving your information:
Iterable<Model> resultModels = modelRepo.findAll();
for (Model resultModel : resultModels) {
System.out.println("Model: " + resultModel.getId() + " " + resultModel.getName());
for (Field resultField : resultModel.getFields()) {
System.out.println("\tField: " + resultField.getId() + " " + resultField.getName());
}
}
Which results in the following, your expected output:
Model: modelId1 Model1
Field: fieldId1 Field1
Field: fieldId2 Field2
Result - graphical representation
I hope that this information proves helpful. Please don't hesitate to ask any unclear items.
I use Neo4J database with Spring Data. I am unable to query (with custom query) a relationship directly to my Relation entity which looks like that:
#RelationshipEntity(type = "OCCURS_WITH")
public class Relation {
#GraphId
private Long id;
#StartNode
#Fetch
private Hashtag from;
#EndNode
#Fetch
private Hashtag to;
#GraphProperty(propertyType = long.class)
private Long[] timestamps = new Long[0];
private boolean active;
// getters, setters
}
I have also a repository interface as follow:
public interface RelationRepository extends CRUDRepository<Relation> {
#Query(value = " MATCH (h1)-[rel]->(h2) " +
" WHERE h1.name = {0} AND h2.name = {1}" +
" RETURN rel")
Relation find(String from, String to);
}
But when I query the repository I get an empty Relation object.
Everything works well when I am quering to dummy object in that way:
#Query(value = " MATCH (h1)-[r]->(h2) " +
" WHERE h1.name = {0} AND h2.name = {1} " +
" RETURN id(r) AS id, h1.name AS from, h2.name AS to, length(r.timestamps) AS size")
RelationshipData findData(String from, String to);
#QueryResult
public interface RelationshipData {
#ResultColumn("id")
String getId();
#ResultColumn("from")
String getFrom();
#ResultColumn("to")
String getTo();
#ResultColumn("size")
int getSize();
}
Is it possible to query directly to my entity?