I'm trying to update existing entry in parent Entity and I encounter error I can't understand nor resolve.
I have two entities in a simple crud repository - Parent(User) and Children(movie). I am trying to pass a favourite movie to an user. The goal is that the movie doesn't have to be already in database, and the #PostMapping has to accept an user_id and movie name as parameters, other method uses the movie name, goes through the OMDBapi, parses data from json to fields and then gives the user at user_id the movie as a favourite. The PostMapping sort of works, because it gets the user at user_id, the movie is also added, but when the url looks like this - http://localhost:8080/users/2/fight+club the user at user_id 2 gets the movie as his favourite, but the movie gets it's id also as 2, even if it's first movie being added to repository. What I don't understand is why when I try to debug this every line of code is acting as I expect it to do -
wUser(id=2, name=Jan, favouriteMovies=[Movie(id=1, title=Fight Club, plot=An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more., genre=Drama, director=David Fincher, posterURL=https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc#._V1_SX300.jpg)])
but after it passes repository.save(user) line I get redirected to InvocableHandlerMethod class, into doInvoke method, into
return KotlinDetector.isSuspendingFunction(method) ? this.invokeSuspendingFunction(method, this.getBean(), args) : method.invoke(this.getBean(), args);
this line, and after that it's just deep into the rabbit hole. As I am quite an inexperienced in coding in Java, what probably can be deducted, I don't really understand nor can find solution to this problem.
The entities and controller classes below
package com.example.omdbapirest.movie;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="movie_id")
private Integer id;
private String title;
private String plot;
private String genre;
private String director;
private String posterURL;
public Movie(String title, String plot, String genre, String director, String posterURL) {
this.title = title;
this.plot = plot;
this.genre = genre;
this.director = director;
this.posterURL = posterURL;
}
}
package com.example.omdbapirest.user;
import com.example.omdbapirest.movie.Movie;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
#Data
#Entity
#NoArgsConstructor
#AllArgsConstructor
public class wUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
// #OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.DETACH})
#OneToMany(cascade =CascadeType.ALL)
#JoinColumn(name = "movie_id")
private List<Movie> favouriteMovies;
public wUser(String name) {
this.name = name;
}
}
UserController
package com.example.omdbapirest.user;
import com.example.omdbapirest.movie.Movie;
import com.example.omdbapirest.movie.MovieService;
import lombok.RequiredArgsConstructor;
import org.json.simple.parser.ParseException;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
#RestController
#RequestMapping("/users")
#RequiredArgsConstructor
public class UserController {
private final MovieService movieService;
private final UserRepository repository;
private final UserService service;
#GetMapping
public List<wUser> getUsers(){
return repository.findAll();
}
#PostMapping("/{id}/{moviename}")
public void addMovieAsFavorite (#PathVariable (name= "id") int id,
#PathVariable (name="moviename") String moviename)
throws ParseException{
String url = "https://www.omdbapi.com/?t="+moviename+"&apikey=30ccf40c";
wUser user = repository.getById(id);
List<Movie> movies = user.getFavouriteMovies();
List<Movie>moviesToAdd = new ArrayList<>();
Movie movie = movieService.getDataFromOMDBAsMovie(url);
movies.add(movie);
moviesToAdd.addAll(movies);
user.setFavouriteMovies(moviesToAdd);
repository.save(user);
}
}
I'm also adding MovieService class in case there is some error in the JSON parser
package com.example.omdbapirest.movie;
import lombok.RequiredArgsConstructor;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.springframework.stereotype.Service;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
#Service
#RequiredArgsConstructor
public class MovieService {
private final MovieRepository repository;
public String getJSONFromURL(String strUrl) {
String jsonText = "";
try {
URL url = new URL(strUrl);
InputStream is = url.openStream();
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(is));
String line;
while ((line = bufferedReader.readLine()) != null) {
jsonText += line + "\n";
}
is.close();
bufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
return jsonText;
}
public Movie getDataFromOMDBAsMovie(String strURL) throws ParseException {
String json = getJSONFromURL(strURL);
Movie movie = new Movie();
JSONParser parser = new JSONParser();
Object object = parser.parse(json);
JSONObject mainJsonObject = (JSONObject) object;
String title = (String)mainJsonObject.get("Title");
movie.setTitle(title);
String plot = (String)mainJsonObject.get("Plot");
movie.setPlot(plot);
String genre = (String)mainJsonObject.get("Genre");
movie.setGenre(genre);
String director = (String)mainJsonObject.get("Director");
movie.setDirector(director);
String posterURL = (String)mainJsonObject.get("Poster");
movie.setPosterURL(posterURL);
repository.save(movie);
return movie;
}
public Movie addMovie(Movie movie){
return repository.save(movie);
}
}
I tried adding movies to db, reworking the favourite saving class, all to no avail, I was getting different errors when not debuging, including
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Pole nie może być NULL"MOVIE_ID"(Field cannot be NULL)
NULL not allowed for column "MOVIE_ID"; SQL statement:
update movie set movie_id=null where movie_id=? [23502-214]
and
org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Naruszenie ograniczenia Klucza Głównego lub Indeksu Unikalnego: "PRIMARY KEY ON PUBLIC.MOVIE(MOVIE_ID)(translating to- Unique Index or primary key violated)
( /* key:2 */ 2, 'David Fincher', 'Drama', 'An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more.', 'https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc#._V1_SX300.jpg', 'Fight Club')"
Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.MOVIE(MOVIE_ID) ( /* key:2 */ 2, 'David Fincher', 'Drama', 'An insomniac office worker and a devil-may-care soap maker form an underground fight club that evolves into much more.', 'https://m.media-amazon.com/images/M/MV5BNDIzNDU0YzEtYzE5Ni00ZjlkLTk5ZjgtNjM3NWE4YzA3Nzk3XkEyXkFqcGdeQXVyMjUzOTY1NTc#._V1_SX300.jpg', 'Fight Club')"; SQL statement:
insert into movie (director, genre, plot, posterurl, title, movie_id) values (?, ?, ?, ?, ?, ?) [23505-214]
Both of these errors appear when I try to add another movie to given user, I mean I was able to give all users 1 movie, but never more since it tries to always add the movie with id of the user
Let's focus on the relevant part of your mapping:
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="movie_id")
private Integer id;
}
and
public class wUser {
#OneToMany(cascade =CascadeType.ALL)
#JoinColumn(name = "movie_id")
private List<Movie> favouriteMovies;
}
The id property of Movie is mapped to the table column movie_id by the configuration in the Movie class.
But for the wUser.favouriteMovies you use #JoinColumn to make it use movie_id the join column, i.e. the column in the Movie table that references the wUser.
By this that column is mapped to two completely different values and it seems in your scenario the second one wins.
To fix this simply choose a different column for the join column. user_id might be a good choice.
Related
I can not fix the error when creating Room Database in Android Studio. Error: stmt.bindLong(1, value.ID);
Also in the database sql queries: "notes", "title", "id" are highlighted in red, as if there is an error here. When trying to compile, it transfers to a file - MainDAO_Impl.java. Shown in the screenshotRoom code:
package com.example.applicationnotes.DataBase;
import android.content.Context;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import com.example.applicationnotes.Models.Notes;
#Database(entities = Notes.class, version = 1, exportSchema = false)
public abstract class RoomDB extends RoomDatabase {
private static RoomDB database;
private static String DATABASE_NAME = "NoteApp";
public synchronized static RoomDB getInstance(Context context){
if (database == null) {
database = Room.databaseBuilder(context.getApplicationContext(),
RoomDB.class, DATABASE_NAME)
.allowMainThreadQueries()
.fallbackToDestructiveMigration()
.build();
}
return database;
}
public abstract com.example.applicationnotes.DataBase.MainDAO mainDao();
}
MainDAO:
package com.example.applicationnotes.DataBase;
import static androidx.room.OnConflictStrategy.REPLACE;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import java.util.List;
import com.example.applicationnotes.Models.Notes;
#Dao
public interface MainDAO {
#Insert (onConflict = REPLACE)
void insert (Notes notes);
#Query ("SELECT * FROM notes ORDER BY id DESC")
List<Notes> getAll();
#Query("UPDATE notes SET title = :title, notes = :notes WHERE ID = :id")
void update (int id, String title, String notes);
#Delete
void delete (Notes notes);
#Query("UPDATE notes SET pinned = :pin WHERE ID = :id")
void pin (int id, boolean pin);
}
More in screenshot:-
https://i.stack.imgur.com/fEkRg.png
https://i.stack.imgur.com/VxDll.png
I tried to change requests, selectors, file names, rummaged through the SQL forums, did not find a solution to my particular problem.
Screenshots with error and SQL-request:
https://i.stack.imgur.com/fEkRg.png
https://i.stack.imgur.com/VxDll.png
I believe that you have removed the member ID from Notes (or possibly removed the Class entirely) and without then compiling the project looked at the MainDAO_Impl.
For example consider:-
#Entity
class Notes {
#PrimaryKey(autoGenerate = true)
long ID;
String title;
String notes;
String date;
boolean pinned;
}
After compiling then MainDAO_Impl is:-
Now if Notes is changed to (long ID; commented out):-
#Entity
class Notes {
#PrimaryKey(autoGenerate = true)
//long ID; /*<<<<<<<<<< COMMENTED OUT >>>>>>>>>>*/
String title;
String notes;
String date;
boolean pinned;
}
Then without compiling MainDAO_Impl is:-
I am learning Swagger. I have a simple Spring Boot REST API to display employee. The Employee model has an association of employee addresses. All I am trying is to display the employee details for the documentation using Swagger.
This is my Employee model:
package com.example.documentation.model;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Arrays;
import java.util.List;
public class Employee<T> {
#Schema(type = "int", description = "id for employee")
private int id;
#Schema(type = "string", description = "name of employee")
private String name;
private List<T> listOfAddresses;
public Employee(int id, String name, List<T> listOfAddresses) {
this.listOfAddresses = listOfAddresses;
this.id = id;
this.name = name;
}
public List<T> getListOfAddresses() {
listOfAddresses = (List<T>) Arrays.asList(new Address(2201,"Street 1","UB12
1TT"), new Address(3201,"Street 1","KK12 1TP"));
return listOfAddresses;
}
public void setListOfAddresses(List<T> listOfAddresses) {
this.listOfAddresses = listOfAddresses;
}}
where Address is a normal POJO with houseNumber, Streetname and postcode.
Below is my controller:
package com.example.documentation.controller;
import com.example.documentation.model.Address;
import com.example.documentation.model.Employee;
import io.swagger.v3.oas.annotations.Operation;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
#RestController
public class EmployeeController {
private Employee<Address> employee;
#RequestMapping("/employee/{id}")
#Operation(
tags = {"Employee"}
)
public Employee<Address> getEmployeeDetailsById(#PathVariable(name = "id", required = true) int id,
#PathVariable(name = "name", required = false) String name) {
List<Address> list = Arrays.asList(new Address(101,"T1","Test 1"),
new Address(201,"T2","Test 2"));
employee = new Employee<>(101,"David", list);
return employee;
}
}
I am using Gradle.
When I access Swagger UI, I see the following:
As you can see the ID and the name of the employee is missing. Any idea how to resolve this?
I have a List private List<Lesson> lessons; and I need to save this list to PostgreSQL database column with data type _json or json[] (JSON array). But I get one of these errors:
ERROR: column "lessons" is of type json[] but the expression is of
type character varyingorERROR: malformed array literal:
"[{"id":17,"title":"Lesson 1","part":1.0}]
How correctly serialize List to get the correct format of Postgresql JSON array?
You might need to use JsonBinaryType class from com.vladmihalcea:hibernate-types library and apply json (or jsonb) to the column definition:
// LessonList.java
import com.vladmihalcea.hibernate.type.json.JsonBinaryType;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
#Entity
#Table(name = "lessons")
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
#TypeDef(name = "json", typeClass = JsonBinaryType.class)
public class LessonList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Type(type = "json")
#Column(columnDefinition = "json")
private List<Lesson> lessons;
}
SQL Script to create the table:
CREATE TABLE "lessons" (
"id" Serial NOT NULL,
"lessons" JSON NOT NULL,
"created_at" Timestamp Without Time Zone DEFAULT NOW() NOT NULL,
PRIMARY KEY ("id")
);
The rest of the classes are to provide working example:
// Lesson.java
#Getter
#Setter
#Builder
#AllArgsConstructor
#NoArgsConstructor
#ToString
public class Lesson {
private int id;
private String title;
private double part;
}
A repository extending Spring CrudRepository interface and DAO class are trivial.
A command line runner to run test:
#Slf4j
#Component
public class TestJson implements CommandLineRunner {
#Autowired
private LessonListDao dao;
#Override
public void run(String[] args) {
List<Lesson> lessons = Arrays.asList(
Lesson.builder().id(11).title("Physics").part(1.0).build(),
Lesson.builder().id(12).title("Chemistry").part(2.0).build(),
Lesson.builder().id(13).title("Biology").part(3.0).build()
);
LessonList list = LessonList.builder().lessons(lessons).build();
LessonList result = dao.save(list);
LOGGER.info("result: " + result);
List<LessonList> all = dao.findAll();
all.forEach(a -> LOGGER.info("item #" + a.getId() + "; lessons=" + a.getLessons()));
}
}
Output:
lesson.TestJson : result: lesson.LessonList#6166aac5
lesson.TestJson : item #1; lessons=[Lesson(id=1, title=Math, part=1.0), Lesson(id=2, title=English, part=2.0), Lesson(id=3, title=Informatics, part=3.0)]
lesson.TestJson : item #2; lessons=[Lesson(id=11, title=Physics, part=1.0), Lesson(id=12, title=Chemistry, part=2.0), Lesson(id=13, title=Biology, part=3.0)]
DB Data: SELECT * FROM "public".lessons:
**id** **lessons** **created_at**
[PK] Integer json timestamp without timezone
1 [{"id":1,"title":"Math","part":1.0}, 2020-06-03 18:08:55.948007
{"id":2,"title":"English","part":2.0},
{"id":3,"title":"Informatics","part":3.0}]
2 [{"id":11,"title":"Physics","part":1.0}, 2020-06-03 18:27:06.565191
{"id":12,"title":"Chemistry","part":2.0},
{"id":13,"title":"Biology","part":3.0}]
Update
This library does not support json[] type because it could be rather redundant.
The example below uses plain JDBC + ObjectMapper to handle specific PostgreSQL array of json
Main point is that you need to use getArray method of ResultSet and then convert the String values inside PGobject to your object
ConfigurableEnvironment environment = (ConfigurableEnvironment) applicationContext.getEnvironment();
DataSource ds = DataSourceBuilder.create()
.username(environment.getProperty("ds.pgsql.username"))
.password(environment.getProperty("ds.pgsql.password"))
.url(environment.getProperty("ds.pgsql.url")).build();
try (Connection connection = ds.getConnection();
PreparedStatement ps = connection.prepareStatement("SELECT id, lessons FROM lesson");
ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
int id = rs.getInt("id");
Object[] arrLessons = (Object[]) rs.getArray("lessons").getArray();
List<Lesson> jsonLessons = Arrays.stream(arrLessons)
.map(PGobject.class::cast)
.map(lesson -> convert(lesson.getValue()))
.collect(Collectors.toList());
System.out.println(id + "; converted: " + jsonLessons);
}
}
//...
private Lesson convert(String value) {
try {
return mapper.readValue(value, Lesson.class);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}
Output
1; converted: [Lesson(id=1, title=Math, part=0.0), Lesson(id=2, title=English, part=0.0)]
2; converted: [Lesson(id=3, title=Physics, part=0.0), Lesson(id=4, title=Chemistry, part=0.0)]
I am having two Entities:
Aircraft
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.jpa.domain.AbstractPersistable;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
//#ToString
public class Aircraft extends AbstractPersistable<Long> {
private String name;
#ManyToOne
private Airport airport;
#Override
public String toString(){
return name;
}
}
And Airport:
public class Airport extends AbstractPersistable<Long> {
private String identifier;
private String name;
#OneToMany(mappedBy = "airport")
private List<Aircraft> aircrafts = new ArrayList<>();
#Override
public String toString(){
String aircraftString = aircrafts.stream().map(r -> r.toString()).collect(Collectors.joining(", "));
return "airport " + name + " " + "[" + aircraftString + "]";
}
}
And a #PostMapping in #Controller like this:
#PostMapping("/aircrafts/{aircraftId}/airports")
public String assignAirport(#RequestParam Long airportId,#PathVariable Long aircraftId){
Aircraft aircraft = aircraftRepository.getOne(aircraftId);
Airport airport = airportRepository.getOne(airportId);
aircraft.setAirport(airport);
aircraftRepository.save(aircraft)
System.out.println(airport.toString());
System.out.println(aircraft.toString());
return "redirect:/aircrafts";
}
This works. But I can not figure out how does this
private List<Aircraft> aircrafts = new ArrayList<>();
List get updated?
I first figured it should work like this in #Controller
airport.getAircrafts().add(aircraft);
But that does not do anything.
The OneToMany relation in the airport class only reflecting what is persisted in the ManyToOne relation in the aircraft class so whenever you will add a new plane that has an airport, this airport planes List will be updated.
Side Note:
If you want to achieve the behavior you were expecting you can add
#OneToMany(mappedBy = "airport", cascade = CascadeType.ALL)
private List<Aircraft> aircrafts = new ArrayList<>();
public void addAircraft(Aircraft aircraft){
aircraft.setAirport(this);
aircrafts.add(aircraft);
}
to your airport class and then save the airport entity.
but I think this isn't what you want and also it's not beneficial in your current case
I am trying to persist an entity incrementally.
Here is an overview of the Entity class
package aop.web.teacher.rmodels;
// Generated 11 Feb, 2011 3:57:41 PM by Hibernate Tools 3.2.2.GA
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.validator.constraints.NotEmpty;
/**
* AopTeacherMaster generated by hbm2java
*/
#Entity
#Table(name="aop_teacher_master"
,schema="public"
)
public class AopTeacherMaster implements java.io.Serializable {
private long id;
private AopTeachersDistrictMaster aopTeachersDistrictMasterByCurrDistrict;
private AopInstitutionmaster aopInstitutionmaster;
private AopTeachersDistrictMaster aopTeachersDistrictMasterByPermDistrict;
#NotEmpty(message="Fathers name is mandatory")
private String fathersName;
#NotEmpty
private String currAddLine1;
private String currAddLine21;
private String currAddLine22;
private String currAddLine3;
private String currDevelopmentBlock;
private String currPoliceStation;
private String currCity;
private String currPin;
private String currState;
private String currCountry;
private String permAddLine1;
private String permAddLine21;
private String permAddLine22;
private String permAddLine3;
private String permDevelopmentBlock;
private String permPoliceStation;
private String permCity;
private String permPin;
private String permState;
private String permCountry;
private Date dateOfBirth;
private Character gender;
private Character maritalStatus;
private String religion;
private String caste;
private String landLineNumber;
private String mobileNumber;
private String email;
private String uidNum;
private String bankName;
private String bankBranch;
private String bankAccountNum;
private String gpfNum;
private Set aopTeachersSanctionedPostDetailsForCurrentIncumbentId = new HashSet(0);
private Set aopTeachersSanctionedPostDetailsForFirstIncumbentId = new HashSet(0);
public AopTeacherMaster() {
}
public AopTeacherMaster(long id) {
this.id = id;
}
Now I have a 2 step wizard like process where in the first screen
user enters some of the properties of the entity and the entity gets merged,
In the second step additional or rest of the properties are filled.
I am using spring 3 annotation based controller where I am using the entity class
as the command object.
On the first go entity gets saved with screen one values then I am sending the
reference from merge as command object for second screen.
However, second screen seems to populate the entries there but nullifies the
existing properties which were from the first screen.
Here is the controller code for the same
#RequestMapping(value = "/insertteacher.html", method = RequestMethod.POST)
public
String testEm(#Valid AopTeacherMaster teacher, BindingResult result,
Map model) {
logger.info("Checking Teacher for error");
if (result.hasErrors()) {
logger.info("User data has:" + result.getErrorCount() + " errors!");
// ////////////////////
for (Object object : result.getAllErrors()) {
if (object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
logger.error("Error on field::" + fieldError.getField()
+ " || error type ::" + fieldError.getCode());
}
}
model.put("smessage", "There was an error");
return "teachersmasterInsert";
}
logger.info("Attemped saving!");
teacher=schoolMasterService.add(teacher);//recieved the reference after merge! Will be used for command object in the next screen
model.put("teacher", teacher);//This is the command object for second screen
model.put("smessage", "teacher inserted successfully");
return "teachersmasterInsert2";
// List myList=testDaoService.findAllTeachers();
// for(Teachermaster t:myList){logger.info("Got::"+t.getId());}
}
#RequestMapping(value = "/insertteacher2.html", method = RequestMethod.POST)
public
String testEm2(#Valid AopTeacherMaster teacher, BindingResult result,
Map model) {
logger.info("Checking Teacher for error second insert");
if (result.hasErrors()) {
logger.info("User data has:" + result.getErrorCount() + " errors!");
// ////////////////////
for (Object object : result.getAllErrors()) {
if (object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
logger.error("Error on field::" + fieldError.getField()
+ " || error type ::" + fieldError.getCode());
}
}
model.put("smessage", "There was an error");
return "teachersmasterInsert";
}
logger.info("Attemped saving!");
teacher=schoolMasterService.add(teacher);
model.put("teacher", teacher);
model.put("smessage", "teacher second instance inserted successfully");
return "teachersmasterInsert";
// List myList=testDaoService.findAllTeachers();
// for(Teachermaster t:myList){logger.info("Got::"+t.getId());}
}
Is this the correct way to do it? Otherwise
how can I achieve this incremental save?
Please suggest!
thanks in advance.
The typical way to implement wizards in annotation based controller is to store partially constructed object in the session, and save it only after the last step:
#Controller
// Model attribute with name "aopTeacherMaster" is transparently stored in the session
#SessionAttribute("aopTeacherMaster")
public class TeacherController {
...
#RequestMapping(value = "/insertteacher2.html", method = RequestMethod.POST)
public String testEm2(#Valid AopTeacherMaster teacher, BindingResult result, Map model) {
...
// No need to save teacher here
}
#RequestMapping(value = "/insertteacherLast.html", method = RequestMethod.POST)
public String testEmLast(#Valid AopTeacherMaster teacher, BindingResult result,
Map model, SessionStatus status) {
...
// Save teacher at the last step
teacher=schoolMasterService.add(teacher);
// Remove it from the session
status.setComplete();
}
}
Alternatively, if you really need incremental save for some reason, you can load the current state of the entity from the database and copy fields with data from the model object manually.