On my application I have multiple entities like:
#Entity
#Data
#Builder
#ToString(of = {"id", "code", "nameContentType", "observations"})
#EqualsAndHashCode(exclude = "room")
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "desk")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Desk implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#Column(name = "code")
private String code;
#Lob
#Column(name = "name")
private byte[] name;
#Column(name = "name_content_type")
private String nameContentType;
#Column(name = "observations")
private String observations;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(unique = true)
private Coordinates coordinates;
#OneToMany(mappedBy = "desk")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<Reservation> reservations = new HashSet<>();
#ManyToOne
#JoinColumn(name = "room_id", insertable = false, updatable = false)
#JsonIgnoreProperties(value = "desks", allowSetters = true)
private Room room;
}
All relationships represented with a collection are cached with #Cache(usage = CacheConcurrencyStrategy.READ_WRITE).
When I delete some records of related Entities I get:
javax.persistence.EntityNotFoundException: Unable to find com.**.domain.Reservation with id ***
I don't know if I have to make any extra adjustments to my cache settings or how to debug the problem
Are you sure you updated Hibernate to the latest version 5.4.32.Final? If so, and you still have the problem, please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.
Related
I have two entity with name of the article and article Category.
and they have one-to-many relationships.
I use #JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class,property = "id")
but I cant see data of article category(category_id) in spring data rest.
ArticleCategory.class
#Entity
#Table(name = "article_category")
#Getter
#Setter
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "articleCategory", fetch = FetchType.LAZY)
private Set<Article> articles = new HashSet<>();
}
Article.class
#Entity
#Table(name = "article")
#Getter
#Setter
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Article implements Serializable {
public Article() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", nullable = false)
private ArticleCategory articleCategory;
#Column(name = "title")
private String title;
#Column(name = "image_url")
private String image_url;
#Column(name = "short_description")
private String short_description;
#Column(name = "text")
private String text;
#Column(name = "keywords", nullable = true)
private String keywords;
#Column(name = "visit", nullable = false)
private int visit;
#Column(name = "code", nullable = false)
private UUID code;
#Column(name = "date_created")
#CreationTimestamp
private Date dateCreated;
#Column(name = "date_updated", nullable = false)
#UpdateTimestamp
private Date dateUpdated;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
public Article(String title, String image_url, String short_description, String text, String keywords, int visit, UUID code) {
this.title = title;
this.image_url = image_url;
this.short_description = short_description;
this.text = text;
this.keywords = keywords;
this.visit = visit;
this.code = code;
}
}
Article Repository
#CrossOrigin("http://localhost:4200")
#RepositoryRestResource(collectionResourceRel = "article", path = "article")
public interface ArticleRepository extends JpaRepository<Article,Long> {
Article findByCode(UUID uuid);
}
And this is output of spring data rest
enter image description here
That is exactly because you used #JsonManagedReference and #JsonBackReference. Keep in mind the following when using them:
#JsonManagedReference is the forward part of the relationship and is the one that gets serialized normally.
#JsonBackReference is the back part of the relationship and it will be omitted from serialization.
The serialized Article object does not contain a reference to the ArticleCategory object.
If you want to have any ArticleCategory data when serializing Article you can either use #JsonIdentityInfo so that one of the properties is serialized (in this case I've chosen id for both):
#Entity
#Table(name = "article")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Article implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id", nullable = false)
private ArticleCategory articleCategory;
}
#Entity
#Table(name = "article_category")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "articleCategory" ,fetch = FetchType.LAZY)
private Set<Article> articles=new HashSet<>();
}
If you are only interested in categoryId another possibility would be to use #JsonIgnore on private Set<Article> articles property so that it is not serialized:
#Entity
#Table(name = "article_category")
#Getter
#Setter
public class ArticleCategory implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "category_name")
private String categoryName;
#JsonIgnore
#OneToMany(cascade = CascadeType.ALL,mappedBy = "articleCategory" ,fetch = FetchType.LAZY)
private Set<Article> articles=new HashSet<>();
}
If none of those suits your needs you might need to implement your own custom serializer. You can read more about all those options at https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion.
I solved the problem using the controller
And that's why #JsonManageRefrence and #JsonBackRefrence do not work
I replaced the lazy load with the eager load in both entity
#ManyToOne(fetch = FetchType.Eager)
#JoinColumn(name = "user_id")
#JsonManageRefrence
private User user;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "articleCategory",
fetch = FetchType.Eager)
#JsonBackRefrence
private Set<Article> articles = new HashSet<>();
and then add a controller
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#RestController
#RequestMapping("/getAllArticle")
public class MyController {
private ArticleRepository articleRepository;
// you must do constructor injection
#GetMapping("/getAllArticle")
public List<Article> allArticle()
{
return articleRepository.findAll();
}
}
I have a project that is split between multiple modules, each module is imported into the main one as a maven dependency.
Persistence entities can be located at any of the projects but under the same package.
I have been trying to improve the startup time of the application by using the spring-context-indexer but it seems to cause an issue with detecting entities.
My #EntityScan is configured like this:
#EntityScan(basePackages = {"com.botscrew", "com.botscrew.demoadminpanel.entity.jpa","com.botscrew.admin.entity"})
The strange thing is that error looks like this
org.hibernate.AnnotationException: #OneToOne or #ManyToOne on com.botscrew.admin.entity.Bot.amioWhatsAppConfigs references an unknown entity: com.botscrew.admin.entity.services.configs.AmioWhatsAppConfigs
Essentially both entities are located under the same package but Bot entity was resolved but AmioWhatsAppConfigs was not.
The application starts perfectly fine without spring indexer.
I am using spring boot 2.2.1.RELEASE
Entities classes:
#Getter
#Setter
#Builder
#Entity
#ToString(of = {"id", "name"})
#AllArgsConstructor
#Table(name = "admin_bot")
#DiscriminatorValue("Bot")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Bot {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Convert(converter = EmojiConverter.class)
private String name;
private Integer timezone;
private String greetingText;
#Column(columnDefinition = "tinyint(1) default 1")
private Boolean active;
#Column(unique = true, updatable = false, nullable = false)
private String publicIdentifier;
#OneToOne(fetch = FetchType.LAZY)
private PersistentMenuEntity persistentMenuEntity;
//TODO FetchType.LAZY
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "widget_id")
private Widget widget;
//TODO FetchType.LAZY
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private MessengerConfigs messengerConfigs;
//TODO FetchType.LAZY
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private AmioWhatsAppConfigs amioWhatsAppConfigs;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private TwilioConfigs twilioConfigs;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private DialogflowConfigs dialogflowConfigs;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private ChatbaseConfig chatbaseConfig;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private SupportSettings supportSettings;
#OneToMany
private Set<Tag> tags;
#OneToMany(mappedBy = "bot")
private List<Broadcast> broadcasts;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "admin_bot_features",
joinColumns = {#JoinColumn(name = "bot_id")},
inverseJoinColumns = {#JoinColumn(name = "feature_id")})
private Set<Feature> features;
public Bot() {
this.active = true;
}
public Bot(String name, DefaultWidgetProperties defaultWidgetProperties) {
this.publicIdentifier = UUID.randomUUID().toString();
this.chatbaseConfig = new ChatbaseConfig();
this.amioWhatsAppConfigs = new AmioWhatsAppConfigs();
this.timezone = 0;
this.name = name;
this.active = true;
this.messengerConfigs = new MessengerConfigs();
this.dialogflowConfigs = new DialogflowConfigs();
this.widget = new Widget(defaultWidgetProperties);
this.supportSettings = new SupportSettings(false);
}
}
#Getter
#Setter
#Entity
#Accessors(chain = true)
#ToString
#Table(name = "admin_amio_whatsapp_configs")
public class AmioWhatsAppConfigs implements AmioWhatsAppBot {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String channelId;
private String accessToken;
private String secret;
}
Please help
I am editing my answer please check example
#EntityScan(basePackages = {"com.botscrew",
"com.botscrew.demoadminpanel.entity.jpa","com.botscrew.admin.entity.services.configs.*"})
I have an app with Angular front end and Spring backend. The two classes in question here are (backend):
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "tournament_games")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TournamentGame {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "code", foreignKey = #ForeignKey(name = "code_fk"))
private TournamentCode code;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "type", foreignKey = #ForeignKey(name = "game_type_fk"))
private GameType type;
#Column(name = "home_score")
private int home_score;
#Column(name = "away_score")
private int away_score;
#ManyToOne(fetch = FetchType.EAGER, optional = false)
#JoinColumn(name = "result_type", foreignKey = #ForeignKey(name = "result_type_fk"))
private ResultType result_type;
#Column(name = "status")
private boolean status;
#Column(name = "round")
private int round;
#Column(name = "locked")
private boolean locked;
#OneToMany(mappedBy = "game", fetch = FetchType.EAGER)
private List<TournamentGamesPlayers> players = new ArrayList<>();
}
and
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#Entity
#Table(name = "tournament_games_players")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "game")
public class TournamentGamesPlayers implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne
#JoinColumn(name = "tournament_game_id")
private TournamentGame game;
#Id
#ManyToOne
#JoinColumn(name = "playerid")
private Player player;
#Column(name = "home")
private boolean home;
}
I need help figuring out how to persist the List<TournamentGamesPlayers> when I save and/or update a TournamentGame object. I generate 45 games. The first 30 games have known players, and so I set them before saving. The last 15 do not have entries for the TournamentGamesPlayers join table, because I need to add them later.
I am able to get some results with CascadeType.ALL on the #OneToMany side when I initially generate the games, but it fails when I try to update a game with a seemingly infinite recursion/stack overflow.
If I omit any cascade type, the games side get generated, but the join table #ManyToOne side does not get entered.
I ended up just putting the players back into the game table to make my life easier.
try putting CascadeType.MERGE, CascadeType.ALL "delete parent and orphans" (JPA CascadeType.ALL does not delete orphans).
Also, defining the relationship as EAGER and not ignoring the JSON property can have problems. I would add #JsonIgnore to one of the parts of the relationship
I have two tables, table A and table B.
#Entity
#Table(name = "A")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class A implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Size(max = 250)
#Column(name = "name", length = 250, nullable = false, unique = true)
private String name;
#OneToMany(mappedBy = "aitems")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<B> bItems = new HashSet<>()
#Entity
#Table(name = "B")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class B implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Size(max = 250)
#Column(name = "name", length = 250, nullable = false)
private String name;
#ManyToOne
#JsonIgnoreProperties("bItems")
private A aItems;
I can create post request for table A and Table B, but if i create a post for A , and after a post for B with relation to the item A that was before created , i want to be able do send a Get request to A and see the B item, but i can only seem them after i reboot my aplication, because when i do the first A post it's stays on cache without any B item.
How can i ignore this without removing it from the domain.
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
Depending on your implementation, you may be able to take advantage of #CacheEvict. Check out the docs, they show you how you can evict A's cache when a POST to B occurs.
Hope this helps
I have two JPA entities: User and Message.
Each Message has one sender and one receiver of type User. And on the other side each User has two sets of type Message: inbox and outbox.
Message:
#Entity
#Table(name = "messages")
public class Message {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "seq")
#SequenceGenerator(name = "seq", sequenceName = "MESSAGES_SEQ")
#Column(name = "ID", insertable = false, updatable = false)
private int id;
#ManyToOne
#JoinColumn(name = "SENDER")
private User sender;
#ManyToOne
#JoinColumn(name = "RECEIVER")
private User receiver;
private String subject, content;
private Date sdate;
//getters and setters
}
All the properties which not being mapped with an annotation has he same name as the columns in database and are automatically mapped by JPA.
User:
#Entity
#Table(name = "users")
public class User {
#Column(name = "USERNAME")
private String username;
#Column(name = "PASSWORD")
private String pass;
#Column(name = "EMAIL")
private String email;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "seq")
#SequenceGenerator(name = "seq", sequenceName = "USERS_SEQ")
#Column(name = "ID", insertable = false, updatable = false)
private int id;
#OneToMany(mappedBy = "uploader")
private Set<Book> books;
#OneToMany(mappedBy = "receiver")
private Set<Message> inbox;
#OneToMany(mappedBy = "sender")
private Set<Message> outbox;
//getters and setters
}
The problem is, when I select an User from Oracle database, then the inbox property is empty. How is this caused and how can I solve it?