Entity not mapped to a single property error with inherited entites of one table - spring-boot

I have two entities SuperAlbumEntity and AlbumEntity reflecting the same table "albums".
SuperAlbumEntity:
#Entity
#Table(name = "albums")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class SuperAlbumEntity {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
//other fields
}
AlbumEntity:
#EqualsAndHashCode(callSuper = true)
#Entity
#Table(name = "albums")
public class AlbumEntity extends SuperEntity{
//some fields
#Column(name = "country")
private String country;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "country_name", referencedColumnName = "country")
private Set<CountryEntity> countrySet = new HashSet<>();
}
AlbumEntity has #OneToMany mapping to CountryEntity:
#Entity
#Table(name = "countries")
public class CountryEntity implements Serializable {
#Id
String id;
String country_name;
//other fields
}
Running my application I get the folowing error:
...
Caused by: org.hibernate.AnnotationException: referencedColumnNames(country) of CountryEntity.countrySet referencing AlbumEntity not mapped to a single property
...
What's interesting is that if I move country field from SuperAlbumEntity to AlbumEntity everything just works fine...
Can someone explain me why I get this error?

I'm not sure but I think is connected with the type of inherence that you used it. Try to modify your superclass to something like this:
SuperAlbumEntity:
#MappedSuperclass
public abstract class SuperAlbumEntity {
}
AlbumEntity:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name = "albums")
public class AlbumEntity extends SuperEntity {
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "country_name", referencedColumnName = "country")
private Set<CountryEntity> countrySet = new HashSet<>();
}

Related

How to implements entity with 2 entity as primary key with jpa annotation and repository

i want to implement a many to many association with quantity information in it . like this :
#Entity
#Table(name = "reserves")
#Getter #Setter #NoArgsConstructor
public class Reserve {
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin bloodGroup;
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Banque banque;
private int quantity;
}
the GroupSanguin and the Banque are two class stored in the database two . here is the code for the two if you need :
#Entity
#Table(name = "groupe_sanguins")
public class GroupeSanguin {
#Id
private String groupe;
#OneToMany(mappedBy = "groupeSanguin")
private List<Donneur> donneurs;
}
#Entity #Getter #Setter #NoArgsConstructor
public class Banque {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true,nullable = false)
private String nom;
private String adresse;
#Column(unique = true)
private String telephone;
private String localisation;
}
so my i want to know how to annotate the JpaRepository to take the two as primary key like this and is my annotation good for it to work ?
public interface ReserveRepository extends JpaRepository<
Reserve,
//what to put here ?
>
This isn't a JPA question in fact, it's a relationnal database conception.
If Reserve has is own data and links with other entity it has it own Id
You can add unicity constraint
#Entity
#Table(name = "reserves", uniqueConstraints={
#UniqueConstraint(columnNames = {"banque_id", "groupe_id"})
#Getter #Setter #NoArgsConstructor
public class Reserve {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin bloodGroup;
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "banque_id")
private Banque banque;
private int quantity;
}
i've found this solutions too.
#Entity
#Table(name = "reserves")
#Getter #Setter #NoArgsConstructor
#IdClass(ReserveId.class) //this annotation will tell that id that the
// the id will be represented by a class
public class Reserve {
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "groupe_id")
private GroupeSanguin groupeSanguin;
#Id
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinColumn(name = "banque_id")
private Banque banque;
private int quantity;
}
and the id class should implements Serializable like this :
#Getter #Setter
public class ReserveId implements Serializable {
private Banque banque;
private GroupeSanguin groupeSanguin;
}
and finally the repository will be like that :
#Repository
public interface ReserveRepo extends JpaRepository<Reserve, ReserveId>{}
See your Reserve class has nowhere mentioned composite primary key. First you need to fix the model, You can refer to the solution here How to create and handle composite primary key in JPA

#OnetoMany entity in #ElementCollection

I have 2 entities and 1 embeddable object :
#Entity
class CourseDetails extends Course {
#Id
Integer id;
#ElementCollection
#CollectionTable(name = "course_section", joinColumns = #JoinColumn(name = "courseId"), foreignKey = #ForeignKey(name = "course_section_fk"))
private List<CourseSection> courseSection;
}
#Embeddable
public class CourseSection extends BaseBo {
#OneToMany
#JoinColumn(name="contentId")
private Set<CourseContent> courseContent = new HashSet<>();
}
#Entity
public class CourseContent {
private static final long serialVersionUID = 1856738483334146418L;
#Id
private Integer contentId;
private String contentSummary;
}
I want to store coursesection as an embedded object of course and course_section should contain reference of course_content. I tried the above structure but it gives error :
#ElementCollection cannot be used inside an #Embeddable that is also contained within an #ElementCollection
How to achieve this in spring boot-jpa ?

How to use #NamedEntityGraph with #EmbeddedId?

I'm trying to have Spring Data JPA issue one query using joins to eagerly get a graph of entities:
#Entity
#NamedEntityGraph(name = "PositionKey.all",
attributeNodes = {#NamedAttributeNode("positionKey.account"),
#NamedAttributeNode("positionKey.product")
})
#Data
public class Position {
#EmbeddedId
private PositionKey positionKey;
}
#Embeddable
#Data
public class PositionKey implements Serializable {
#ManyToOne
#JoinColumn(name = "accountId")
private Account account;
#ManyToOne
#JoinColumn(name = "productId")
private Product product;
}
Here's my Spring Data repo:
public interface PositionRepository extends JpaRepository<Position, PositionKey> {
#EntityGraph(value = "PositionKey.all", type = EntityGraphType.LOAD)
List<Position> findByPositionKeyAccountIn(Set<Account> accounts);
}
This produces the following exception:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [positionKey.account] on this ManagedType
I want all of the accounts and products to be retrieved in one join statement with the positions. How can I do this / reference the embedded ID properties?
I would suggest refactoring the entity this way if it possible
#Entity
#NamedEntityGraph(name = "PositionKey.all",
attributeNodes = {#NamedAttributeNode("account"),
#NamedAttributeNode("product")
})
#Data
public class Position {
#EmbeddedId
private PositionKey positionKey;
#MapsId("accountId")
#ManyToOne
#JoinColumn(name = "accountId")
private Account account;
#MapsId("productId")
#ManyToOne
#JoinColumn(name = "productId")
private Product product;
}
#Embeddable
#Data
public class PositionKey implements Serializable {
#Column(name = "accountId")
private Long accountId;
#Column(name = "productId")
private Long productId;
}
Such an EmbeddedId is much easier to use. For instance, when you are trying to get an entity by id, you do not need to create a complex key containing two entities.

Springboot add problem in oneTOMany relation

I'm writing 3 tables in the following relation:
Club class:
#Setter
#Getter
#Entity
#Table(name = "Club")
public class Club {
#Id
#GeneratedValue
private Long id;
private String name;
private String type;
private String mainPage;
private String logo;
#OneToMany(mappedBy="clubProductKey.club", cascade = CascadeType.ALL)
#JsonIgnoreProperties(value = "clubProductKey.club", allowSetters=true)
private Set<ClubProduct> clubProducts;
...
Product class:
#Setter
#Getter
#Entity
#Table(name = "Product")
public class Product {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="clubProductKey.product", cascade = CascadeType.ALL)
#JsonIgnoreProperties(value = "clubProductKey.product", allowSetters=true)
private Set<ClubProduct> clubProducts;
...
ClubProduct class:
#Setter
#Getter
#Entity
#Table(name = "ClubProduct")
public class ClubProduct {
#EmbeddedId
private ClubProductKey clubProductKey;
...
ClubProductKey class:
#Setter
#Getter
#Embeddable
public class ClubProductKey implements Serializable {
#ManyToOne(cascade = {CascadeType.MERGE,CascadeType.REFRESH })
#JoinColumn(name = "club_id", referencedColumnName = "id")
#JsonIgnoreProperties(value = "clubProducts", allowSetters=true)
private Club club;
#ManyToOne(cascade = {CascadeType.MERGE,CascadeType.REFRESH })
#JoinColumn(name = "product_id", referencedColumnName = "id")
#JsonIgnoreProperties(value = "clubProducts", allowSetters=true)
private Product product;
...
ClubProductRepository class:
public interface ClubProductRepository extends JpaRepository<ClubProduct, ClubProductKey> {
public List<ClubProduct> findByClubProductKeyClub(Club club);
public List<ClubProduct> findByClubProductKeyProduct(Product product);
}
I try to save clubProduct like this:
#Service
public class ClubProductServiceImp implements ClubProductService {
#Autowired
private ClubProductRepository clubProductRepository;
...
ClubProduct savedClubProduct = clubProductRepository.save(clubProduct);
return savedClubProduct;
}
However I find that the clubProduct is not saved in the clubProducts list in the club or product entity, the list is null. Must I add lines like club.getClubProducts.add(clubProduct) or is there any other way to make it added automatically?
Thank you.
The #OnetoMany mapping in your Club class uses the attribute mappedby which means that it represents the owning side of the relation responsible for handling the mapping. However, we still need to have both sides in sync as otherwise, we break the Domain Model relationship consistency, and the entity state transitions are not guaranteed to work unless both sides are properly synchronized.
The answer is yes, you have to manage the java relations yourself so that the clubProducts gets persisted. You are using an instance of the repository class club to persist the data so , you should add a setter method like :
public void addClubProduct(ClubProduct clubProduct) {
if (clubProduct!= null) {
if (clubProduct== null) {
clubProduct= new ArrayList<ClubProduct>();
}
clubProducts.add(clubProduct);
clubProduct.setClubProduct(this);
}
}
also a method to remove it from the list and use these method in your code to set the values to the list properly before initiating save . Read related article

JPA Composite PK referenced by FKs in One to Many Relationship

I am trying to map the tables below into JPA. The relationships are one-to-many between user_tax and tax and user_tax and user. It has confused me the fact that i have a composite primary key, and i need to map the foreign keys to these 2 keys.
the error message: org.hibernate.AnnotationException: mappedBy reference an unknown target entity property: entity.Tax.user_tax in entity.UserTax.taxs
tax user_tax user
-------- -------- ------
PK|t_id |--------| t_id |PK-FK |u_name|
|t_name| PK-FK| u_id |-------|u_id | PK
| | | name | | |
Here is my Entities:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="u_name")
private String uname;
getters + setters
}
#Entity
#Table(name = "tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Tax implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "t_name")
private String tname;
#Embeddable
public class UserTaxId implements Serializable {
#Column(name="u_id")
private Long uId;
#Column(name="t_id")
private Long tId;
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user_tax")
private List<User> users;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user_tax")
private List<Tax> taxs;
Your 1:n mappings are backwards (i.e. a UserTax can have only a single User and a single Tax) and you are using a derived identity. Try mapping UserTax like this:
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("uId") // maps uId attribute of embedded id
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("tId") // maps tId attribute of embedded id
private Tax tax;
...
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
I will post here what worked for me after 3 days of research.
Brian Vosburgh correctly posted the UserTax class:
#Entity
#Table(name = "user_tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class UserTax implements Serializable {
#EmbeddedId
private UserTaxId userTaxId;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("uId") // maps uId attribute of embedded id
private User user;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("tId") // maps tId attribute of embedded id
private Tax tax;
...
}
However, i was getting error meassages and my code wasn't compiling. Then i also had to edit the User and Tax classes:
#Entity
#Table(name = "user")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(
mappedBy = "tid",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserTax> tax = new ArrayList<>();
#Column(name="u_name")
private String uname;
getters + setters
}
#Entity
#Table(name = "tax")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Tax implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(
mappedBy = "uid",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserTax> taxs = new ArrayList<>();
#Column(name = "t_name")
private String tname;
setters+getters
}
Here is the link where i found the solution to my problem: https://vladmihalcea.com/the-best-way-to-map-a-many-to-many-association-with-extra-columns-when-using-jpa-and-hibernate/

Resources