How to map only values of HashMap - Hibernate - java

I'd like to map only the values of a map to database.
In the example below, in class Holder, there's a map of ID, Entity, being the ID a BigInteger and the entity Item.
I'm doing this because I want fast search and hashmap K,V is good for that.
But, now, the mapping is weird.
The JoinTable holder_items now has 3 columns, holder_id. item_id and item_KEY.
Can I have only older_id and item_Id?
Basically, mapping only items.values() to the current Holder.
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "holder_items",
joinColumns = #JoinColumn(name = "holder_id"),
inverseJoinColumns = #JoinColumn(name = "item_id")
)
private Map<BigInteger, Item> items = new HashMap<>();
//(...)
}
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
//(...)
}

You could do this mapping without the third table if it is not necessary ofc. Example:
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#MapKey(name = "id")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy="holder")
private Map<BigInteger, Item> items = new HashMap<>();
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
#ManyToOne
private Holder holder;
}

Solution with help of #Anthony
#Entity
public class Holder {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#MapKey(name = "id")
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "holder_items",
joinColumns = #JoinColumn(name = "holder_id"),
inverseJoinColumns = #JoinColumn(name = "item_id")
)
private Map<BigInteger, Item> items = new HashMap<>();
-
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(columnDefinition = "BIGINT")
private BigInteger id;
}
Results in table holder_items with holder_id and item_id, as desired!

Related

How to set value for all OneToMany entities?

I have an ClientUser entity with #OneToMany field customField:
#Entity
#Data
public class ClientUser {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(
name = "client_user_custom_field",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "field_id", referencedColumnName = "id"))
private Collection<ClientFieldValue> customFields;
}
And a ClientFieldValue entity:
#Entity
#Data
public class ClientFieldValue {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String value;
}
How can I create ClientFieldValue's for all existing ClientUser?
I know that I can do smth like:
final Iterable<ClientUser> clientUsers = userRepository.findAll();
clientUsers.forEach(clientUser ->
clientUser.setCustomFields(Collections.singleton(new ClientFieldValue())));
userRepository.saveAll(clientUsers);
But I don't want to query all and save them after set.
Is there another way to do this?

Hibernate loads list collection twice

I have 3 tables in my database, container, item and item_container which is a join_table of many to one between container and item. Entities in code are mapped using 2 classes: Container and Item.
The relation is unidrectional from Container to Item.
join_table in hibernate is mapped only by annotations in Container class.
#Entity
#Table(name="container")
public class Container {
#Id
#Column(name = "container_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinTable(name = "item_container",
joinColumns = #JoinColumn(name = "container_id"),
inverseJoinColumns = #JoinColumn(name = "item_id"))
private Set<Item> items;
//getter/setters
}
My problem is: when i have the type of collection Set<Item> items changed to List<Item>, the list contain every Item entity twice. I cant find the reason why, the hashCode and equals methods of Item are based only on the item_id field.
UPDATE:
Code for Item class:
#Entity
#Table(name = "item")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "item_template_id", nullable = false)
private ItemTemplate itemTemplate;
#Column(name = "item_group")
#Enumerated(EnumType.STRING)
private ItemGroup itemGroup;
#Column(name = "amount")
private int amount;
//getter/setters
}

Select records without parent with Hibernate using Criteria API

How select records without parent with Hibernate using Criteria API?
Here is my Java code for select with parents
getSessionFactory().getCurrentSession().createCriteria(Category.class).add(
Restrictions.eq("parent", new Category(parentId))).list();
Category Java code
#Entity
#Table(name = "CATEGORY")
public class Category implements NamedModel{
#Id
#Column(name = "CATEGORY_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToOne(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
#JoinTable(name = "CATEGORY_RELATIONS",
joinColumns = {
#JoinColumn(name = "CATEGORY_RELATIONS_CATEGORY_ID", referencedColumnName = "CATEGORY_ID")},
inverseJoinColumns = {
#JoinColumn(name = "CATEGORY_RELATIONS_PARENT_ID", referencedColumnName = "CATEGORY_ID")})
private Category parent;
#OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER, mappedBy = "parent")
private List<Category> children;//...
}
CategoryRelations Java code
#Entity
#Table(name = "CATEGORY_RELATIONS")
#IdClass(CategoryRelations.CategoryRelationsPrimaryKey.class)
public class CategoryRelations implements Serializable {
#Id
#Column(name = "CATEGORY_RELATIONS_CATEGORY_ID")
private long categoryId;
#Id
#Column(name = "CATEGORY_RELATIONS_PARENT_ID")
private long parentId;
#Entity
#IdClass(CategoryRelationsPrimaryKey.class)
public static class CategoryRelationsPrimaryKey implements Serializable {
private long categoryId;
private long parentId;
}
}
You can use Restriction#isNull(propertyName) function for your requirements.
Restrictions.isNull("parent")

Hibernate mapping many columns to one table

How to configure mapping? I want to table "Remittance" were two columns referring to the table "Expense"
Remittance
#Entity
#Table(name = "REMITTANCE")
public class Remittance implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "REMITTANCE_ID")
private Long id;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "remittances", cascade = CascadeType.ALL)
private Expense from;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "remittances", cascade = CascadeType.ALL)
private Expense to;
}
Expense
#Entity
#Table(name = "EXPENSE")
public class Expense implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "EXPENSE_ID")
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "REMITTANCE_ID")
private Remittance remittances;
}
I made a mistake. I have corrected
Remittance
#Entity
#Table(name = "REMITTANCE")
public class Remittance implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "REMITTANCE_ID")
private Long id;
#ManyToOne(optional = false)
#JoinColumn(name = "EXPENSE_ID")
private Expense from;
#ManyToOne(optional = false)
#JoinColumn(name = "EXPENSE_ID")
private Expense to;
}
Expense
#Entity
#Table(name = "EXPENSE")
public class Expense implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "EXPENSE_ID")
private Long id;
}
but now out
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: ru.make.alex.web.model.revenue.Remittance column: EXPENSE_ID (should be mapped with insert="false" update="false")

spring-data-rest, manytomany relation with join table

Is it possible to expose a manytomany relationship that uses a join entity (that contains extra data columns), below is my entities;
I'm trying to get 'purchases' to show in REST, I've put in 'products' as an example of a working REST mapping;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = Purchase.class, orphanRemoval = true)
#JoinColumn(name = "user_id", updatable = false)
private List<Purchase> purchases = new ArrayList<>();
#ManyToMany
#JoinColumn(name = "user_id", updatable = false)
private List<Product> products = new ArrayList<>();
}
#Entity
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
}
#Entity
public class Purchase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#ManyToOne
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
#ManyToOne(targetEntity = Prodect.class)
#JoinColumn(name = "product_id", referencedColumnName = "id")
private Product product;
#Column(name = "purchase_date")
private Date purchaseDate;
}
So if i send the REST call;
[GET http://localhost:8080/webapp/users/1]
It returns links for [http://localhost:8080/webapp/users/1/products] but not for [http://localhost:8080/webapp/users/1/purchases]
worked out what the issue was; I need to create a JpaRepository for the Purchase entity. Soon as I added that, the REST links for purchases are available.

Categories