I'm trying to map the following table to an entity.
The mapping for the event table looks like this:
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer _id;
#Column(name = "title")
private String _title;
#Column(name = "description")
private String _description;
#Column(name = "location")
private String _place;
#Column(name = "start")
private Date _start;
#Column(name = "end")
private Date _stop;
#Column(name = "points")
private int _points;
#Enumerated(EnumType.STRING)
#Column(name = "type")
private EventType _eventtype;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "event2work2instrumentation", joinColumns = {
#JoinColumn(name = "event")},
inverseJoinColumns = {#JoinColumn(name = "work")})
private Set<WorkMapper> _works = new HashSet<>(0);
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "event2work2instrumentation", joinColumns = {
#JoinColumn(name = "event")},
inverseJoinColumns = {#JoinColumn(name = "instrumentation")})
private Set<InstrumentationMapper> _instrumentations = new HashSet<>(0);
It works fine and i get all the data from the database, but when I try to store a new event which has a work and instrumentation assigned to it I get errors.
When the fields in the event2work2instrumentation table are configured to not be null, i get: field does not have a default value.
If I give the field default values I get:
SQLIntegrityConstraintViolationException: Cannot add or update a child row:
a foreign key constraint fails (`schema`.`event2work2instrumentation`, CONSTRAINT `e2w2i_instrumentation_fk` FOREIGN KEY (`instrumentation`) REFERENCES `instrumentation` (`id`))
You have any ideas? May it depend on the Mappings of instrumentation and/or Work? These classes do not have a reference to event2work2instrumentation in their mapping.
Try truncating both tables and then store the new FK. It happened to me when I had a object_related_id which wasn't in object table as an id
The solution is to use a map and the MapKeyJoinColumn annotation:
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "event2work2instrumentation", joinColumns = {
#JoinColumn(name = "event")},
inverseJoinColumns = {#JoinColumn(name = "instrumentation")})
#MapKeyJoinColumn(name = "work")
private Map<WorkMapper, InstrumentationMapper> _eventToWorkAndInstrumentationMappers = new HashMap<>();
Related
I have two entities - User and Song:
User.class:
#Entity
#Table(name = "users")
public class User {
#Id
#Column(name = "user_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "login",unique = true)
private String login;
#Column(name = "password")
private String password;
#Column(name = "token")
private UUID token;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "users_songs",
joinColumns = #JoinColumn(
name = "u_id",
referencedColumnName = "user_id"
),
inverseJoinColumns = #JoinColumn(
name = "s_id",
referencedColumnName = "song_id"
)
)
private List<Song> songs = new ArrayList<>();
}
Song.class:
#Entity
#Table(name = "songs")
public class Song {
#Id
#Column(name = "song_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "song_title")
private String songTitle;
#Column(name = "composer_name")
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "composers")
#OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn(name = "composer_id")
private Set<String> composer;
#Column(name = "author_of_words_name")
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "author_of_words")
#OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn(name = "authorOfWords_id")
private Set<String> authorOfWords;
#Column(name = "song_artist")
private String songArtist;
#Column(name = "song_timing")
private int songTiming;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
#JoinColumn(name = "user_id_key")
private User user;
#Column(name = "rate_value")
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "rating")
#MapKeyColumn(name = "login")
#OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn
private final Map<String, Integer> rating = new HashMap<>();
#Column
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "comment")
#MapKeyColumn(name = "login")
#OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn
private final Map<String, String> comments = new HashMap<>();
}
I want to delete a Song, but not delete a User.
I tried deleting it like this:
Query query = session.createQuery("DELETE Song s WHERE s.user = :user AND s.songTitle = :songTitle");
query.setParameter("user", user);
query.setParameter("songTitle", songTitle);
query.executeUpdate()
But the error drops:
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement...
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "songs" violates foreign key constraint "fka7me64vk6jtx81wt2ggbvm6ur" on table "users_songs"
Key (song_id)=(28) is still referenced from table "users_songs".
I understand that the problem is due to the fact that in the spanning table users_songs, which occurred due to the connection #OneToMany.
I read a similar question in the STO and it says that you need to break the connection. how to delete the record from the join table in hibernate
I executed the following code:
List<Song> collect = user.getSongs().stream().filter(s -> !s.getSongTitle().equals(songTitle)).collect(Collectors.toList());
user.setSongs(collect);
session.update(user);
Query query = session.createQuery("DELETE Song s WHERE s.songTitle = :songTitle");
query.setParameter("songTitle", songTitle);
query.executeUpdate();
This code works, but I don't think it's quite right. Now the question. How do I delete a Song from a user? With the condition that the song should not cascade to delete the user.
Please help me solve this issue correctly. I'd really appreciate it.
You can specify ON DELETE CASCADE for the foreign key constraint fka7me64vk6jtx81wt2ggbvm6ur on the table users_songs like below:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(
name = "users_songs",
joinColumns = #JoinColumn(
name = "u_id",
referencedColumnName = "user_id"
),
inverseJoinColumns = #JoinColumn(
name = "s_id",
referencedColumnName = "song_id"
),
inverseForeignKey = #ForeignKey(
name = "users_songs_songs_FK", // fka7me64vk6jtx81wt2ggbvm6ur renamed to users_songs_songs_FK
foreignKeyDefinition = "FOREIGN KEY (s_id) REFERENCES songs(song_id) ON DELETE CASCADE"
)
)
private List<Song> songs = new ArrayList<>();
and after database schema regeneration your initial query should work as expected.
I have two table in relation many to many
public class Repertoire {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, unique = true)
private Integer id;
private String name;
private Integer dayWeek;
#ManyToMany(cascade = CascadeType.REMOVE)
#JoinTable(
name = "repertoire_seance",
joinColumns = { #JoinColumn(name = "repertoire_id")},
inverseJoinColumns = {#JoinColumn(name = "seance_id")}
)
List<Seance> seances = new ArrayList<>();
}
and
public class Seance {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(nullable = false, unique = true)
private Integer id;
private java.time.LocalTime displayTime;
#ManyToOne
private Film film;
#Column(length=127)
private String kind;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private Hall hall;
#OneToMany(mappedBy = "reservationSeance")
#JsonIgnore
private List<Reservation> reservations = new ArrayList<>();
}
Hibernate create linked tabel repertoire_seance is posible get seances by seancesId and repertoire.dayWeek using spring data (JpaRepository) something like that findBySeanceIdAndRepertoireDayWeek()?
You could achieve this by writing an HQL.
It would look something like this:
select s from Repertoire r inner join r.seances s where r.dayWeek ="Your Value" and s.id = "Your Id Value"
I have a database with several entities, in particular Book and User. Between them there exists a ManyToMany relationship like this:
Book:
#Entity
#Table(name = "Books")
public class Book implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "bookId", nullable = false, unique = true)
private Long id;
#Column(name = "title", nullable = false)
private String title;
#Column(name = "price", nullable = false)
private int price;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "bookId"),
inverseJoinColumns = #JoinColumn(name = "userId"))
private Set<UserAccount> users;
User:
#Entity
#Table(name = "UserAccounts")
public class UserAccount implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "userId", nullable = false, unique = true)
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "bookId"))
Set<Book> purchasedBooks;
Everything works fine, the table User_Book is indeed created in the database. The problem seems to be related to the access of this Table.
For example,
Query query = entityManager.createQuery("SELECT u FROM User_Book u");
keeps telling me the following:
The abstract schema type 'User_Book' is unknown
So, shall I create from scratch the User_Book entity? Will it get automtically populated like now, that is, whenever a user buys a book, will this purchase be recorded in the table?
User_Book is not an entity. Therefore you cannot use createQuery, BUT you can use createNativeQuery to execute a SQL query:
Query query = entityManager.createNativeQuery("SELECT * FROM User_Book");
The result will be List<Object[]>
I have a LibraryModel class, a LibraryImage class and a LibraryAttribute class. A LibraryModel can have an arbitrary number of LibraryImages and LibraryAttributes.
The error that I get:
org.hibernate.MappingException: Foreign key (FKmbn4xh7xdxv371ao5verqueu3:library_item_attribute [LIBRARY_ITEM_ATTRIBUTE_ID])) must have same number of columns as the referenced primary key (library_item_attribute [LIBRARY_ITEM_ID,LIBRARY_ITEM_ATTRIBUTE_ID])
Here are my annotated Objects:
Library Model:
#Entity
#Table(name = "library_item", uniqueConstraints = {
})
#Inheritance(strategy = InheritanceType.JOINED)
public class LibraryItemModel implements LibraryItem{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_ITEM_ID", unique = true, nullable = false)
private Integer libraryItemId;
#Column(name = "ITEM_TITLE", unique = false, nullable = false)
private String itemTitle;
#Column(name = "IS_PARENT", nullable = false)
private Boolean isParent;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ID", nullable = false)
private LibraryModel libraryModel;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "ITEM_LISTING",
joinColumns = {#JoinColumn(name = "PARENT_LIB_ITEM_ID", nullable=false)},
inverseJoinColumns = {#JoinColumn(name="CHILD_LIB_ITEM_ID", nullable = false)})
private Set<LibraryItemModel> itemChildren = new HashSet<>();
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "itemChildren")
private Set<LibraryItemModel> itemParents = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "LIBRARY_ITEM_IMAGE",
joinColumns = { #JoinColumn(name = "LIBRARY_ITEM_ID", nullable=false)},
inverseJoinColumns = { #JoinColumn(name="LIBRARY_IMAGE_ID", nullable = false)})
private Set<LibraryImage> itemImages = new HashSet<>();
#OneToMany(fetch = FetchType.LAZY, mappedBy = "rootLibraryItemModel")
private Set<LibraryModel> libraries = new HashSet<>();
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "LIBRARY_ITEM_ATTRIBUTE",
joinColumns = { #JoinColumn(name = "LIBRARY_ITEM_ID", nullable =false)},
inverseJoinColumns = { #JoinColumn(name="LIBRARY_ITEM_ATTRIBUTE_ID", nullable = false)})
private Set<LibraryItemAttribute> libraryItemAttributes = new HashSet<>();
}
LibraryImage:
#Entity
#Table(name = "library_image", uniqueConstraints = {
})
public class LibraryImage {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_IMAGE_ID", unique = true, nullable = false)
private Integer libraryImageId;
#Column(name = "IMAGE_LOCATION")
private String imageLocation;
#Column(name = "IMAGE_TITLE")
private String imageTitle;
#Enumerated(EnumType.STRING)
private LibraryImageType imageType;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ITEM_ID", nullable = false)
private LibraryItemModel libraryItemModel;
}
Library Attribute:
#Entity
#Table(name = "library_item_attribute", uniqueConstraints = {
})
public class LibraryItemAttribute {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LIBRARY_ITEM_ATTRIBUTE_ID", unique = true, nullable = false)
private Integer libraryItemAttributeId;
#Column(name = "ATTRIBUTE_NAME")
private String attributeName;
#Column(name = "ATTRIBUTE_VALUE")
private String attributeValue;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name="LIBRARY_ITEM_ID", nullable = false)
private LibraryItemModel libraryItemModel;
}
This is really frustrating as the LibraryImage class is mapped without problems and doesn't throw any errors, but the LibraryAttribute class which is annotated in an identical way to the LibraryImage class is throwing this error.
Can someone please have a look and let me know what my problem is?
Found the problem.
In the LibraryItemModel class I defined the Join table with the LibraryItemAttribute to be called "LIBRARY_ITEM_ATTRIBUTE", which is the name of the table of the Library item attributes.
The join table is a different table and should have a different table name.
For the Library Image table above, the image table is called library_image, while the join table is called LIBRARY_ITEM_IMAGE
Given the following entity (some columns omitted from this long definition for brevity):
#Table(name = "Products")
public class Products implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "SKU")
private String sku;
#Basic(optional = false)
#Column(name = "ProductName")
private String productName;
private boolean allowPreOrder;
#ManyToMany(mappedBy = "productsCollection")
private Collection<Categories> categoriesCollection;
#JoinTable(name = "Products_CrossSell", joinColumns = {
#JoinColumn(name = "SKU", referencedColumnName = "SKU")}, inverseJoinColumns = {
#JoinColumn(name = "CrossSKU", referencedColumnName = "SKU")})
#ManyToMany
private Collection<Products> productsCollection;
#ManyToMany(mappedBy = "productsCollection")
private Collection<Products> productsCollection1;
#JoinTable(name = "Products_Related", joinColumns = {
#JoinColumn(name = "SKU", referencedColumnName = "SKU")}, inverseJoinColumns = {
#JoinColumn(name = "RelatedSKU", referencedColumnName = "SKU")})
#ManyToMany
private Collection<Products> productsCollection2;
#ManyToMany(mappedBy = "productsCollection2")
private Collection<Products> productsCollection3;
How do I get the set of related products for a given product SKU?
The products_related table looks like this:
I know how to get the answer using SQL but I'm new to JPA so I haven't quite grokked the API and query syntax yet.
It seems to me there are some unnecessary collections defined. Anyway:
#JoinTable(name = "Products_Related", joinColumns = {
#JoinColumn(name = "SKU", referencedColumnName = "SKU")}, inverseJoinColumns = {
#JoinColumn(name = "RelatedSKU", referencedColumnName = "SKU")})
#ManyToMany
private Collection<Products> productsCollection2;
This piece (it is present in your code) should give you the desired products. Just rename it to relatedProducts, and the respective setter/getter.
Update: You can get the object by:
Product p = entityManager.find(Product.class, yourProductId);
p.getRelatedProducts();
Obtaining the entity manager depends on your setup, and a better place to look for how to obtain it, is a tutorial.