Spring Data "Data too long for column at row" - java

I have 3 tables in my database.FOOD_GROUP, FOOD_DESCRIPTION, SECONDARY_FOOD_DESCRIPTION,. My Application.java parses data files in the correct order so that on table can useful to the next. My issue is that when it comes to setting the databankID field in the SecondaryFoodDescription class, I get Data truncation: Data too long for column 'food' at row 1. This is surprising (at least to me) because, I use the same repository.save method to populate the foodGroup field in the class. Food.
EDIT: I'm aware that normally, an error like Data truncation: Data too long for column 'foodid' at row 1 would mean that what I'm trying to insert is too big for a field. However, I'm trying to insert an Entity. How could my Entity be too big?
Can anyone spot what I'm wrong?
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CommandLineRunner demo(FoodGroupRepository foodGrouprepository, FoodRepository foodRepository,
SecondaryFoodInformationRepository secondaryFoodInformationRepository,
) {
return (args) -> {
FoodGroupParser foodGroupParser = new FoodGroupParser();
FoodGroup foodGroup;
Map<String, String> foodGroupMap = foodGroupParser.returnFoodGroupData();
for (Map.Entry<String, String> entry : foodGroupMap.entrySet()) {
foodGroup = new FoodGroup(entry.getKey(), entry.getValue());
foodGrouprepository.save(foodGroup);
}
FoodDescriptionParser foodDescriptionParser = new FoodDescriptionParser();
List<String[]> listOfFooods = foodDescriptionParser.returnFoodDescriptionData();
Food foodDescription;
SecondaryFoodDescription secondaryFoodDescription;
for (String[] foodItem : listOfFooods) {
foodDescription = new Food(foodItem[0],foodGrouprepository.findOne(foodItem[1]),foodItem[2],foodItem[4],foodItem[5],foodItem[8]);
secondaryFoodDescription = new SecondaryFoodDescription();
foodRepository.save(foodDescription);
secondaryFoodDescription = new SecondaryFoodDescription(foodRepository.findOne(foodItem[0]),foodItem[6],foodItem[7],foodItem[9],foodItem[10],foodItem[11]);
secondaryFoodInformationRepository.save(secondaryFoodDescription);
}
};
}
}
Repository interfaces:
#RepositoryRestResource
public interface FoodGroupRepository extends PagingAndSortingRepository<FoodGroup,String> {
}
#RepositoryRestResource
public interface FoodRepository extends PagingAndSortingRepository<Food, String>{
List<Food> findByLongDescription(#Param("longDescription") String name);
}
#RepositoryRestResource
public interface SecondaryFoodInformationRepository extends PagingAndSortingRepository<SecondaryFoodDescription,Long> {
}
Food group entity:
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
#Entity
#Table(name = "FOOD_GROUP")
public class FoodGroup implements Serializable{
public FoodGroup(){}
public FoodGroup(String id, String foodName){
this.setFoodGroupCode(id);
this.setFoodName(foodName);
}
#Id
#NotNull
#Size(min = 4,max = 4)
private String foodGroupCode;
#NotNull
#Size(max=60)
private String foodName;
public String getFoodGroupCode() {
return foodGroupCode;
}
public void setFoodGroupCode(String foodGroupCode) {
this.foodGroupCode = foodGroupCode;
}
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
}
Food entity:
import javax.persistence.*;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "FOOD_DESCRIPTION")
public class Food implements Serializable {
#Id
#NotNull()
#Column(name = "NUTRITION_DATA_BANK_ID")
#Size(min = 5, max = 5)
private String nutritionDatabankID;
private FoodGroup foodGroupID;
#OneToMany(mappedBy = "foodDescription", cascade = CascadeType.ALL)
private final Set<NutritionDataForSpecificFood> ndesc = new HashSet<>();
public Set<NutritionDataForSpecificFood> getNutrients() {
return Collections.unmodifiableSet(this.ndesc);
}
public void addFood(NutritionDataForSpecificFood specificFood) {
specificFood.setFoodDescription(this);
this.ndesc.add(specificFood);
}
#NotNull
#Column(name = "LONG_DESCRIPTION")
#Size(max = 200)
private String longDescription;
#Size(max = 100)
#Column(name = "COMMON_NAME")
private String commonName;
#Size(max = 65)
#Column(name = "MANUFACTURER_NAME")
private String manufacturerName;
#Size(max = 65)
#Column(name = "SCIENTIFIC_NAME")
private String scientificNameOfFood;
public Food() {
}
public Food(String nutritionDatabankID, FoodGroup foodGroupID, String longDescription, String commonName,
String manufacturerName, String scientificNameOfFood) {
this.nutritionDatabankID = nutritionDatabankID;
this.foodGroupID = foodGroupID;
this.longDescription = longDescription;
this.commonName = commonName;
this.manufacturerName = manufacturerName;
this.scientificNameOfFood = scientificNameOfFood;
}
public FoodGroup getFoodGroupID() {
return foodGroupID;
}
public void setFoodGroupID(FoodGroup foodGroupID) {
}
public String getNutritionDatabankID() {
return nutritionDatabankID;
}
public void setNutritionDatabankID(String nutritionDatabankID) {
this.nutritionDatabankID = nutritionDatabankID;
}
public String getLongDescription() {
return longDescription;
}
public void setLongDescription(String longDescription) {
this.longDescription = longDescription;
}
public String getCommonName() {
return commonName;
}
public void setCommonName(String commonName) {
this.commonName = commonName;
}
public String getManufacturerName() {
return manufacturerName;
}
public void setManufacturerName(String manufacturerName) {
this.manufacturerName = manufacturerName;
}
public String getScientificNameOfFood() {
return scientificNameOfFood;
}
public void setScientificNameOfFood(String scientificNameOfFood) {
this.scientificNameOfFood = scientificNameOfFood;
}
}
Secondary Food Info entity:
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.io.Serializable;
#Entity
#Table(name = "SECONDARY_FOOD_DESCRIPTION")
public class SecondaryFoodDescription implements Serializable {
public SecondaryFoodDescription(){}
public SecondaryFoodDescription(Food food,String refuseDescription, String refusePercentage,
String caloriesFromProteinFactor, String caloriesFromFatFactor,
String caloriesFromCarbsFactor){
this.food = food;
this.refuseDescription = refuseDescription;
this.refuseDescription = refuseDescription;
this.caloriesFromProteinFactor = caloriesFromProteinFactor;
this.caloriesFromFatFactor = caloriesFromFatFactor;
this.caloriesFromCarbsFactor = caloriesFromCarbsFactor;
}
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
public Long getId() {
return id;
}
private Food food;
#Size(max = 135)
#Column(name = "REFUSE_DESCRIPTION")
private String refuseDescription;
#Column(name = "REFUSE_PERCENTAGE")
private String refusePercentage;
#Column(name = "CALORIES_FROM_PROTEIN_FACTOR")
private String caloriesFromProteinFactor;
#Column(name = "CALORIES_FROM_FAT_FACTOR")
private String caloriesFromFatFactor;
#Column(name = "CALORIES_FROM_CARBS_FACTOR")
private String caloriesFromCarbsFactor;
public String getRefuseDescription() {
return refuseDescription;
}
public void setRefuseDescription(String refuseDescription) {
this.refuseDescription = refuseDescription;
}
public String getRefusePercentage() {
return refusePercentage;
}
public void setRefusePercentage(String refusePercentage) {
this.refusePercentage = refusePercentage;
}
public String getCaloriesFromProteinFactor() {
return caloriesFromProteinFactor;
}
public void setCaloriesFromProteinFactor(String caloriesFromProteinFactor) {
this.caloriesFromProteinFactor = caloriesFromProteinFactor;
}
public String getCaloriesFromFatFactor() {
return caloriesFromFatFactor;
}
public void setCaloriesFromFatFactor(String caloriesFromFatFactor) {
this.caloriesFromFatFactor = caloriesFromFatFactor;
}
public String getCaloriesFromCarbsFactor() {
return caloriesFromCarbsFactor;
}
public void setCaloriesFromCarbsFactor(String caloriesFromCarbsFactor) {
this.caloriesFromCarbsFactor = caloriesFromCarbsFactor;
}
public Food getFood() {
return food;
}
public void setFood(Food food) {
this.food = food;
}
}

You need to annotate with appropriate relations #OneToOne/#OneToMany, otherwise the complete object will be serialized and persisted as a BLOB. If the BLOB size is large you get the Data Truncation error.

"Solved" by adding a #OneToOne annotation to the field ,food in the SecondaryFoodDescription entity.
This is an unsatisfying answer though. In the Food entity there is an unannotated field for the entity FoodGroup. That field does not produce the "column to long" error.

Related

Incorrect auto-generated SQL query in Spring Boot (JPA) CrudRepository

My repository interfaces:
SongsRepository:
public interface SongRepository extends CrudRepository<Song, Integer> {
}
AlbumsRepository
public interface AlbumRepository extends CrudRepository<Album, Integer> {
}
My Model classes:
Album.java
#Entity
#Table(name = "albums", schema = "dbo")
public class Album {
#Id
#GeneratedValue
#Column(name = "album_id")
private Integer albumId;
#Column(name = "album_name")
private String albumName;
#Column(name = "released_by")
private String releasedBy;
#Column(name = "total_duration")
private Integer totalDuration;
#OneToMany(targetEntity = Song.class)
private List<Song> songs;
public Integer getAlbumId() {
return albumId;
}
public void setAlbumId(Integer albumId) {
this.albumId = albumId;
}
public String getAlbumName() {
return albumName;
}
public void setAlbumName(String albumName) {
this.albumName = albumName;
}
public String getReleasedBy() {
return releasedBy;
}
public void setReleasedBy(String releasedBy) {
this.releasedBy = releasedBy;
}
public Integer getTotalDuration() {
return totalDuration;
}
public void setTotalDuration(Integer totalDuration) {
this.totalDuration = totalDuration;
}
public List<Song> getSongs() {
return songs;
}
public void setSongs(List<Song> songs) {
this.songs = songs;
}
}
Song.java
#Entity
#Table(name = "songs", schema = "dbo")
public class Song {
#Id
#GeneratedValue
#Column(name = "song_id")
private Integer songId;
#Column(name = "song_name")
private String songName;
#Column(name = "album_id")
private Integer songAlbumId;
#Column(name = "song_duration")
private String songDuration;
#ManyToOne(targetEntity = Album.class)
private Album album;
public Integer getSongId() {
return songId;
}
public void setSongId(Integer songId) {
this.songId = songId;
}
public String getSongName() {
return songName;
}
public void setSongName(String songName) {
this.songName = songName;
}
public Integer getSongAlbumId() {
return songAlbumId;
}
public void setSongAlbumId(Integer songAlbumId) {
this.songAlbumId = songAlbumId;
}
public String getSongDuration() {
return songDuration;
}
public void setSongDuration(String songDuration) {
this.songDuration = songDuration;
}
public Album getAlbum() {
return album;
}
public void setAlbum(Album album) {
this.album = album;
}
}
My Controller:
SongsController.java
#RestController
#RequestMapping("/songs")
public class SongsController {
#Autowired
private SongRepository songs;
#Autowired
private AlbumRepository albums;
#Autowired
private Services services;
#GetMapping("/")
public List<SongViewModel> getAllSongs() {
List<SongViewModel> listOfAllSongs = new ArrayList<>();
songs.findAll().forEach(song -> listOfAllSongs.add(services.translateToViewModel(song)));
return listOfAllSongs;
}
}
Services class:
Services.java:
#Service
public class Services {
#Autowired
private SongRepository songs;
#Autowired
private AlbumRepository albums;
public SongViewModel translateToViewModel(Song song) {
SongViewModel model = new SongViewModel();
model.setSongId(song.getSongId());
model.setSongAlbumId(song.getSongAlbumId());
model.setSongName(song.getSongName());
model.setSongDuration(song.getSongDuration());
model.setSongAlbumName(albums.findById(song.getSongAlbumId()).get().getAlbumName());
return model;
}
public AlbumViewModel translateToViewModel(Album album) {
AlbumViewModel model = new AlbumViewModel();
return model;
}
}
My View Models:
SongViewModel:
public class SongViewModel {
private String songName;
private String songAlbumName;
private String songDuration;
private Integer songId;
private Integer songAlbumId;
public String getSongName() {
return songName;
}
public void setSongName(String songName) {
this.songName = songName;
}
public String getSongAlbumName() {
return songAlbumName;
}
public void setSongAlbumName(String songAlbumName) {
this.songAlbumName = songAlbumName;
}
public String getSongDuration() {
return songDuration;
}
public void setSongDuration(String songDuration) {
this.songDuration = songDuration;
}
public Integer getSongId() {
return songId;
}
public void setSongId(Integer songId) {
this.songId = songId;
}
public Integer getSongAlbumId() {
return songAlbumId;
}
public void setSongAlbumId(Integer songAlbumId) {
this.songAlbumId = songAlbumId;
}
}
Logged SQL query:
select song0_.song_id as song_id1_1_, song0_.album_album_id as album_al5_1_, song0_.album_id as album_id2_1_, song0_.song_duration as song_dur3_1_, song0_.song_name as song_nam4_1_ from dbo.songs song0_
Error:
ERROR: column song0_.album_album_id does not exist
My Database Schema (PostgreSQL 12.10.1)
This is my first time using Spring Boot and JPA. What have I done wrong here?
From the error message, I am guessing that it is trying to find a column called album_album_id which does not exist in my database and as a result is unable to find it; but why is it searching for that particular column? (My guess is I've messed up the relationship attributes).
Your mapping is wrong. Song should look like this:
#Entity
#Table(name = "songs", schema = "dbo")
public class Song {
#Id
#GeneratedValue
#Column(name = "song_id")
private Integer id;
#Column(name = "song_name")
private String name;
#Column(name = "album_id")
private Integer albumId;
#Column(name = "song_duration")
private String duration;
#ManyToOne
#JoinColumn(name = "album_id", insertable = false, updatable = false)
private Album album;
}
and Album like this:
#Entity
#Table(name = "albums", schema = "dbo")
public class Album {
#Id
#GeneratedValue
#Column(name = "album_id")
private Integer id;
#Column(name = "album_name")
private String name;
#Column(name = "released_by")
private String releasedBy;
#Column(name = "total_duration")
private Integer totalDuration;
#OneToMany(mappedBy = "album")
private List<Song> songs;
}
By the way,
it's a little strange to have song duration formatted as String and album duration as Integer.
if you're willing to go from CrudRepository to JpaRepository, you may want to use Spring data projection instead of manually recasting your song to SongViewModels
Here's a little example of interface projection for your question
Your Song entity class should be changed like follows.
#Entity
#Table(name = "songs", schema = "dbo")
public class Song {
#Id
#GeneratedValue
#Column(name = "song_id")
private Integer songId;
#Column(name = "song_name")
private String songName;
#Column(name = "song_duration")
private String songDuration;
#JoinColumn(name = "album_id", referencedColumnName = "album_id")
#ManyToOne
private Album album;
public Integer getSongId() {
return songId;
}
public void setSongId(Integer songId) {
this.songId = songId;
}
public String getSongName() {
return songName;
}
public void setSongName(String songName) {
this.songName = songName;
}
public Integer getSongAlbumId() {
return songAlbumId;
}
public void setSongAlbumId(Integer songAlbumId) {
this.songAlbumId = songAlbumId;
}
public String getSongDuration() {
return songDuration;
}
public void setSongDuration(String songDuration) {
this.songDuration = songDuration;
}
public Album getAlbum() {
return album;
}
public void setAlbum(Album album) {
this.album = album;
}
}
now you can get alubm_id by song enntity using song.getAlbum().getAlbumId()

#ElementCollection does not getting detached

My goal is to clone entity 'Product' with all its filters.
For example, I have an entity (getters and setters omitted for simplicity):
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
}
And embeddable class:
#Embeddable
public class Filter {
#Column(length = 255, nullable = false)
private String name;
#Column(nullable = false)
private long variant = -1;
}
Now, if I do:
entityManager.detach(product);
product.setId(null);
productService.save(product);
I will get a copy of product entity but with filters from original product. In meanwhile original product will end up with no filters at all..
Thats how filter's table rows looks like:
Before:
product_id; name; variant
217; "f2"; 86
After:
product_id; name; variant
218; "f2"; 86
I tried detach each filter from the list but it gives me error.
How can I make it copy filters with an entity?
Edit: Added full Product and Filter code:
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;
import org.hibernate.search.annotations.SortableField;
import org.joda.time.DateTime;
import com.serhiy1.constraint.LocalePacker;
#Indexed
#Entity
#EntityListeners(ProductListener.class)
public class Product {
public static final int PRICE_PER_ONE = 0;
public static final int PRICE_PER_METER = 1;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private Long code;
private String name = "";
private String grouping = "";
#Field
#Column(columnDefinition="text")
private String title = "";
#Field
#Column(columnDefinition="text")
private String intro = "";
#Column(columnDefinition="text")
private String content = "";
#Field
#Column(columnDefinition="text")
private String contentHtml = "";
private String locale = "en";
private Long parentId = 0L;
private DateTime time;
private DateTime timeMod;
private Long balanceRequired = 0L;
private Integer index = 0;
#Field(name = "price_sort")
#SortableField(forField = "price_sort")
private Double price = 0.0;
private Integer pricePer;
#Transient
private long childrenCount = 0;
#Transient
private String image = "";
#Transient
private List<String> images = new ArrayList<String>();
#ManyToOne(targetEntity = User.class)
#JoinColumn(nullable = false, name = "user_id")
#LazyCollection(LazyCollectionOption.FALSE)
private User user;
#ManyToOne(targetEntity = Product.class)
#JoinColumn(nullable = true, name = "category_id")
#LazyCollection(LazyCollectionOption.FALSE)
private Product category;
#ElementCollection()
private List<Filter> filters = new ArrayList<Filter>();
#ElementCollection()
private List<Modifier> modifiers = new ArrayList<Modifier>();
public Product() {
}
#Transient
private String _title = "";
#Transient
private String _intro = "";
#Transient
private String _content = "";
#Transient
private String _contentHtml = "";
public void pack(String locale, List<String> locales) {
if(locale.contains("_")) return;
title = LocalePacker.repack(locale, _title, title, locales);
intro = LocalePacker.repack(locale, _intro, intro, locales);
content = LocalePacker.repack(locale, _content, content, locales);
contentHtml = LocalePacker.repack(locale, _contentHtml, contentHtml, locales);
}
public void unpack(String locale) {
_title = LocalePacker.unpackStr(locale, title).getOrDefault(locale, "");
_intro = LocalePacker.unpackStr(locale, intro).getOrDefault(locale, "");
_content = LocalePacker.unpackStr(locale, content).getOrDefault(locale, "");
_contentHtml = LocalePacker.unpackStr(locale, contentHtml).getOrDefault(locale, "");
}
public void copy(String landFrom, String landTo) {
title = LocalePacker.copyLang(title, landFrom, landTo);
intro = LocalePacker.copyLang(intro, landFrom, landTo);
content = LocalePacker.copyLang(content, landFrom, landTo);
contentHtml = LocalePacker.copyLang(contentHtml, landFrom, landTo);
}
public Modifier getModifier(String name) {
for(Modifier m: modifiers) {
if(m.getName().equals(name)) return m;
}
return null;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public long getCode() {
return code == null ? id : code;
}
public void setCode(long code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGrouping() {
return grouping;
}
public void setGrouping(String grouping) {
this.grouping = grouping;
}
public String getTitle() {
return _title;
}
public void setTitle(String title) {
this._title = title;
}
public String getIntro() {
return _intro;
}
public void setIntro(String intro) {
this._intro = intro;
}
public String getContent() {
return _content;
}
public void setContent(String content) {
this._content = content;
}
public String getContentHtml() {
return _contentHtml;
}
public void setContentHtml(String contentHtml) {
this._contentHtml = contentHtml;
}
public String getLocale() {
return locale;
}
public void setLocale(String locale) {
this.locale = locale;
}
public long getParentId() {
return parentId;
}
public void setParentId(long parentId) {
this.parentId = parentId;
}
public DateTime getTime() {
return time;
}
public void setTime(DateTime time) {
this.time = time;
}
public DateTime getTimeMod() {
return timeMod;
}
public void setTimeMod(DateTime timeMod) {
this.timeMod = timeMod;
}
public long getBalanceRequired() {
return balanceRequired == null ? 0L : balanceRequired;
}
public void setBalanceRequired(long balanceRequired) {
this.balanceRequired = balanceRequired;
}
public Integer getIndex() {
//return index == null ? 1000 : index;
return index;
}
public void setIndex(Integer index) {
this.index = index;
}
public double getPrice() {
return price == null ? 0.0 : price;
}
public void setPrice(double price) {
this.price = price;
}
public int getPricePer() {
return pricePer == null ? PRICE_PER_METER : pricePer;
}
public void setPricePer(int pricePer) {
this.pricePer = pricePer;
}
public long getChildrenCount() {
return childrenCount;
}
public void setChildrenCount(long childrenCount) {
this.childrenCount = childrenCount;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public List<String> getImages() {
return images;
}
public void setImages(List<String> images) {
this.images = images;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Product getCategory() {
return category;
}
public void setCategory(Product category) {
this.category = category;
}
public List<Filter> getFilters() {
return filters;
}
public void setFilters(List<Filter> filters) {
this.filters = filters;
}
public List<Modifier> getModifiers() {
return modifiers;
}
public void setModifiers(List<Modifier> modifiers) {
this.modifiers = modifiers;
}
public boolean isCategory() { return price < 0; }
#Override
public String toString() {
return "Article{" +
"id=" + id +
'}';
}
}
..
package com.serhiy1.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Transient;
#Embeddable
public class Filter {
#Column(length = 255, nullable = false)
private String name;
#Column(nullable = false)
private long variant = -1;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVariant() {
return variant;
}
public void setVariant(long variant) {
this.variant = variant;
}
}
I made a mini project trying to replicate your issue.
It is a String Boot project with H2 database and JPA (Hibernate implementation).
On startup, Hibernate creates 2 tables:
create table product (
id bigint not null,
primary key (id)
)
and
create table product_filters (
product_id bigint not null,
name varchar(255) not null,
variant bigint not null
)
On product with filters creation, both tables get inserted:
insert
into
product
(id)
values
(1)
and
insert
into
product_filters
(product_id, name, variant)
values
(1, "f1", 1)
After:
entityManager.detach(product);
product.setId(null);
productService.save(product);
Hibernate issues:
delete
from
product_filters
where
product_id=1
which is normal, since filters is an ElementCollection therefore it is totally owned by the entity Product. On productService.save(product) Hibernate detects that filters collection is bound to another Product therefore deletes the old bound (from product_filter table) before creating a new one.
The only way to overcome the deletion is to recreate the collection:
List<Filter> filters = new ArrayList<Filter>();
filters.addAll(oldFilters);
product.setFilters(filters);
To sum up, here is the solution:
// To trigger the fetch
List<Filter> filters = new ArrayList<Filter>(product.getFilters());
entityManager.detach(product);
product.setId(null);
product.setFilters(filters);
productService.save(product);

Writing model class for song table : Spring boot, postgres

Here is my table design
**Songs
Movie Id - integer
[year] - integer
Song name - character
Set Singers(list) - text
Lyrics writer(list) -text
Length - numeric(3,2)**
I am developing a rest service using spring boot . I tried to implement a pojo where I am not getting good result.
here is my developed model class
#Entity
public class SongsInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
Long id;
int year;
#ElementCollection
List<String> singers;
#ElementCollection
List<String> lyricists;
float length;
public SongsInfo() {
}
public int getYear() {
return year;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setYear(int year) {
this.year = year;
}
public List<String> getSingers() {
return singers;
}
public void setSingers(List<String> singers) {
this.singers = singers;
}
public List<String> getLyricists() {
return Lyricists;
}
public void setLyricists(List<String> lyricists) {
Lyricists = lyricists;
}
public float getLength() {
return length;
}
public void setLength(float length) {
this.length = length;
}
/* public MoviesInfo getMoviesInfo() {
return moviesInfo;
}
#Access(AccessType.PROPERTY)
#ManyToOne
#JoinColumn(name = "movieId")
public void setMoviesInfo(MoviesInfo moviesInfo) {
this.moviesInfo = moviesInfo;
}*/
}
Please help me to write a model class where I can implement all the CRUD operations .
My expectaion of data in the table:
MovieId year Song name setofsingers lyricists length
CA1532 2015 adiga adiga hemachandra, roopa ram,sirivennala 5:46
If your expectation is a column you should not be using #ElementCollection as it will create one table each. (songs_info, songs_info_lyricists, songs_info_singers).
You can use a model like this, where you save a simple column but then retrieving a List and removing the get and set for simple singers and liricists:
The model:
import java.util.ArrayList;
import java.util.Arrays;
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;
#Entity
#Table(name = "songs_info")
public class SongsInfo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private int year;
#Column
private String singers;
#Column
private String lyricists;
private float length;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public List<String> getSingersList() {
if(this.singers != null){
return Arrays.asList(this.singers.split(","));
}else
return new ArrayList<String>();
}
public void setSingersList(List<String> singersList) {
this.singers = String.join(",", singersList);
}
public List<String> getLyricistsList() {
if(this.lyricists != null){
return Arrays.asList(this.lyricists.split(","));
}else
return new ArrayList<String>();
}
public void setLyricistsList(List<String> lyricistsList) {
this.lyricists = String.join(",", lyricistsList);
}
public float getLength() {
return length;
}
public void setLength(float length) {
this.length = length;
}
}
The repo :
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.web.bind.annotation.CrossOrigin;
import com.atos.travel.models.SongsInfo;
#RepositoryRestResource(collectionResourceRel = "songs", path = "songs")
#CrossOrigin("*")
public interface SongsRepository extends PagingAndSortingRepository<SongsInfo, Long> {
}
Then your post should be like that:
{ "length": "5.39", "lyricistsList": ["ram","Hemanth" ], "singersList": [ "hema","roopa" ], "year": 2005}
You can do it like this:
#SpringBootApplication
public class So45179111Application {
public static void main(String[] args) {
SpringApplication.run(So45179111Application.class, args);
}
public static class ListToCommaTextConverter implements AttributeConverter<List<String>, String> {
#Override
public String convertToDatabaseColumn(List<String> attribute) {
if (attribute == null || attribute.isEmpty()) {
return null;
}
return attribute.stream().collect(Collectors.joining(","));
}
#Override
public List<String> convertToEntityAttribute(String dbData) {
if (dbData == null || dbData.isEmpty()) {
return Collections.emptyList();
}
return Stream.of(dbData.split(",")).collect(Collectors.toList());
}
}
#Entity
#Table(name = "Movies")
public static class MoviesInfo extends AbstractPersistable<Long> {
private String name;
// getters and setters
}
#Entity
#Table(name = "Songs")
public static class SongsInfo extends AbstractPersistable<Long> {
#Column(columnDefinition = "text")
#Convert(converter = ListToCommaTextConverter.class)
private List<String> singers;
#Column(columnDefinition = "text")
#Convert(converter = ListToCommaTextConverter.class)
private List<String> lyricists;
#Column(columnDefinition = "numeric(3,2)")
private float length;
private int year;
#ManyToOne
#JoinColumn(name = "movie_id", foreignKey = #ForeignKey(name = "Songs_Movies_fk1"))
private MoviesInfo movie;
// getters and setters
}
#RestController
#RequestMapping("/songs")
public static class SongsApi {
private final SongsInfoRepository songsInfoRepository;
#Autowired
public SongsApi(SongsInfoRepository songsInfoRepository) {
this.songsInfoRepository = songsInfoRepository;
}
#PostMapping
public SongsInfo store(#RequestBody SongsInfo songsInfo) {
return songsInfoRepository.save(songsInfo);
}
}
}
interface SongsInfoRepository extends CrudRepository<So45179111Application.SongsInfo, Long> {}
And you can use your request:
$ curl -XPOST -H'Content-Type: application/json' -d '{ "length": 5.39, "lyricists": [ "ram","Hemanth" ], "singers": [ "hema","roopa" ], "year": 2005 }' localhost:8080/songs
{"id":3,"singers":["hema","roopa"],"lyricists":["ram","Hemanth"],"length":5.39,"year":2005,"movie":null,"new":false}%

org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table

I have a problem that Hibernate is unable to determine the type for Collection at the table Region. I am trying to create a foreign key of table Actels through one-to-many relationship. a region can have many actels.
In detail:
The error I am getting is this:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Collection, at table: Region, for columns: [org.hibernate.mapping.Column(collection_actels)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:316)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:294)
at org.hibernate.mapping.Property.isValid(Property.java:238)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:469)
at org.hibernate.mapping.RootClass.validate(RootClass.java:270)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1294)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1742)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:94)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:905)
... 20 more
Region.java:
package com.springJPA.domain;
import java.io.Serializable;
import java.lang.String;
import java.util.Collection;
import javax.persistence.*;
import com.springJPA.domain.Actels;
/**
* Entity implementation class for Entity: Reseau
*
*/
#Entity
public class Region implements Serializable {
private int id_region;
private String region;
private String ville;
private int codep;
private int num_region;
private int num_ville;
private Collection<Actels> collection_actels;
private static final long serialVersionUID = 1L;
private Collection<Actels> actels;
public Region() {
super();
}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence_region")
#SequenceGenerator(name = "id_Sequence_region", sequenceName = "ID_SEQ_REGION")
public int getId_region() {
return id_region;
}
public void setId_region(int id_region) {
this.id_region = id_region;
}
public String getRegion() {
return this.region;
}
public void setRegion(String region) {
this.region = region;
}
public String getVille() {
return this.ville;
}
public void setVille(String ville) {
this.ville = ville;
}
public int getCodep() {
return this.codep;
}
public void setCodep(int codep) {
this.codep = codep;
}
public Collection<Actels> getCollection_actels() {
return collection_actels;
}
public void setCollection_actels(Collection<Actels> collection_actels) {
this.collection_actels = collection_actels;
}
public int getNum_region() {
return num_region;
}
public void setNum_region(int num_region) {
this.num_region = num_region;
}
public int getNum_ville() {
return num_ville;
}
public void setNum_ville(int num_ville) {
this.num_ville = num_ville;
}
#OneToMany
#JoinColumn(name = "Region_id_region", referencedColumnName = "id_region")
public Collection<Actels> getActels() {
return actels;
}
public void setActels(Collection<Actels> param) {
this.actels = param;
}
}
Actels.java:
package com.springJPA.domain;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
/**
* Entity implementation class for Entity: Actels
*
*/
#Entity
public class Actels implements Serializable {
private int id_actels;
private String nomActels;
private int num_actel;
private Region region;
private static final long serialVersionUID = 1L;
public Actels() {
super();
}
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "id_Sequence_actels")
#SequenceGenerator(name = "id_Sequence_actels", sequenceName = "ID_SEQ_ACTELS")
public int getId_actels() {
return id_actels;
}
public void setId_actels(int id_actels) {
this.id_actels = id_actels;
}
public String getNomActels() {
return this.nomActels;
}
public void setNomActels(String nomActels) {
this.nomActels = nomActels;
}
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public int getNum_actel() {
return num_actel;
}
public void setNum_actel(int num_actel) {
this.num_actel = num_actel;
}
}
Put any JPA annotation above each field instead of getter property:
#SequenceGenerator(name = "id_Sequence_actels", sequenceName = "ID_SEQ_ACTELS")
private int id_actels;
And:
#JoinColumn(name = "Region_id_region", referencedColumnName = "id_region")
private Collection<Actels> actels;
#Column
#ElementCollection(targetClass=String.class)
public Set<String> getOptions() {
return options;
}
OR
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "....")
public Set<String> getOptions() {
return options;
}

substract two fields in java each time i add a new record

How can i substract two fieldes using jpa;
i want to get soldejours(class contrat) = soldejours(classe contrat) - dureeassitance (classe assitance)
i have to do this operatio each time i persist a new assistance
here's the class Assistance
package model.entitie;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.SecondaryTable;
#Entity
#NamedQueries({ #NamedQuery(name = "Contrat.findAll", query = "select o from Contrat o") })
public class Contrat implements Serializable {
#Column(length = 4000)
private String annee;
#Column(length = 4000)
private String client;
#Id
#Column(name = "ID_CONTRAT", nullable = false, length = 4000)
private String idContrat;
#Column(length = 4000)
private String information;
#Column(name = "NB_JOURS")
private BigDecimal nbJours;
#Column(name = "SOLDE_JOURS")
private BigDecimal soldeJours;
#OneToMany(mappedBy = "contrat",cascade=CascadeType.PERSIST)
private List<Assistance> assistanceList;
public Contrat() {
}
public Contrat(String annee, String client, String idContrat, String information, BigDecimal nbJours,
BigDecimal soldeJours) {
this.annee = annee;
this.client = client;
this.idContrat = idContrat;
this.information = information;
this.nbJours = nbJours;
this.soldeJours = soldeJours;
}
public String getAnnee() {
return annee;
}
public void setAnnee(String annee) {
this.annee = annee;
}
public String getClient() {
return client;
}
public void setClient(String client) {
this.client = client;
}
public String getIdContrat() {
return idContrat;
}
public void setIdContrat(String idContrat) {
this.idContrat = idContrat;
}
public String getInformation() {
return information;
}
public void setInformation(String information) {
this.information = information;
}
public BigDecimal getNbJours() {
return nbJours;
}
public void setNbJours(BigDecimal nbJours) {
this.nbJours = nbJours;
}
public BigDecimal getSoldeJours() {
return soldeJours;
}
public void setSoldeJours(BigDecimal soldeJours) {
this.soldeJours = soldeJours;
}
public List<Assistance> getAssistanceList() {
return assistanceList;
}
public void setAssistanceList(List<Assistance> assistanceList) {
this.assistanceList = assistanceList;
}
public Assistance addAssistance(Assistance assistance) {
getAssistanceList().add(assistance);
assistance.setContrat(this);
return assistance;
}
public Assistance removeAssistance(Assistance assistance) {
getAssistanceList().remove(assistance);
assistance.setContrat(null);
return assistance;
}
}
and this is the class Assistance
package model.entitie;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
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.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#NamedQueries({ #NamedQuery(name = "Assistance.findAll", query = "select o from Assistance o") })
public class Assistance implements Serializable {
private static final long serialVersionUID = 7916354262572083045L;
#Column(length = 4000)
private String client;
#Temporal(TemporalType.DATE)
#Column(name = "DATE_CREATION")
private Date dateCreation;
#Column(name = "DUREE_ASSISTANCE")
private BigDecimal dureeAssistance;
#Column(name = "ETAT_ASSISTANCE", length = 4000)
private String etatAssistance;
#Id
#Column(name = "ID_ASSISTANCE", nullable = false, length = 4000)
private String idAssistance;
#Column(name = "ING_AFF", length = 4000)
private String ingAff;
#Column(name = "OUVERT_PAR", length = 4000)
private String ouvertPar;
#Column(name = "SUJET_ASS", length = 4000)
private String sujetAss;
#ManyToOne(cascade= CascadeType.PERSIST)
#JoinColumn(name = "CONTRAT_ID",updatable =true,insertable =true)
private Contrat contrat;
public Assistance() {
}
public Assistance(String client, Contrat contrat, Date dateCreation, BigDecimal dureeAssistance,
String etatAssistance, String idAssistance, String ingAff, String ouvertPar, String sujetAss) {
this.client = client;
this.contrat = contrat;
this.dateCreation = dateCreation;
this.dureeAssistance = dureeAssistance;
this.etatAssistance = etatAssistance;
this.idAssistance = idAssistance;
this.ingAff = ingAff;
this.ouvertPar = ouvertPar;
this.sujetAss = sujetAss;
}
public String getClient() {
return client;
}
public void setClient(String client) {
this.client = client;
}
public Date getDateCreation() {
return dateCreation;
}
public void setDateCreation(Date dateCreation) {
this.dateCreation = dateCreation;
}
public BigDecimal getDureeAssistance() {
return dureeAssistance;
}
public void setDureeAssistance(BigDecimal dureeAssistance) {
this.dureeAssistance = dureeAssistance;
}
public String getEtatAssistance() {
return etatAssistance;
}
public void setEtatAssistance(String etatAssistance) {
this.etatAssistance = etatAssistance;
}
public String getIdAssistance() {
return idAssistance;
}
public void setIdAssistance(String idAssistance) {
this.idAssistance = idAssistance;
}
public String getIngAff() {
return ingAff;
}
public void setIngAff(String ingAff) {
this.ingAff = ingAff;
}
public String getOuvertPar() {
return ouvertPar;
}
public void setOuvertPar(String ouvertPar) {
this.ouvertPar = ouvertPar;
}
public String getSujetAss() {
return sujetAss;
}
public void setSujetAss(String sujetAss) {
this.sujetAss = sujetAss;
}
public Contrat getContrat() {
return contrat;
}
public void setContrat(Contrat contrat) {
this.contrat = contrat;
}
}
Use Entity listeners and Callback methods.
#PrePersist and #PostPersist
#PreUpdate and #PostUpdate
#PreRemove and #PostRemove
#PostLoad
https://docs.jboss.org/hibernate/entitymanager/3.5/reference/en/html/listeners.html

Categories