Spring cascade field not updated - spring

I have an object with the following attribute but when I try to save the object this field is not merging.
How can I solve the issue ?
#ManyToMany(targetEntity = User.class, mappedBy = "userSites", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#NotAudited
private List<IUser> localIt;
userSites:
#BatchSize(size = 20)
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Site.class)
#JoinTable(name = "USER_SITE",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "SITE_ID", nullable = false) })
private Set<ISite> userSites;

Instead of save the attribute :
#ManyToMany(targetEntity = User.class, mappedBy = "userSites", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#NotAudited
private List<IUser> localIt;
I updated the site list of each users by adding the site to register into the concerned field :
#BatchSize(size = 20)
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Site.class)
#JoinTable(name = "USER_SITE",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "SITE_ID", nullable = false) })
private Set<ISite> userSites;

Related

Springboot ExampleMatcher always returns no result

I have the following entity and I'm trying to use ExampleMatcher for simple queries:
#Entity(name="UserAccount")
#Table(name = "useraccount", catalog = "useraccount")
#Data
public class UserAccount implements Serializable
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false, unique = true)
private String mail;
private String password;
private boolean isEnabled;
private Timestamp credentialExpire;
private boolean isAccountNonLocked;
private boolean isSuspended;
private Timestamp accountExpire;
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#JoinTable(name = "user_to_privileges", catalog = "useraccount",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "privilege_id", referencedColumnName = "id", nullable = false)})
private Set<Privilege> privileges= new HashSet<>();
#ManyToMany(cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#JoinTable(name = "user_to_organizations", catalog = "useraccount",
joinColumns = {#JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)},
inverseJoinColumns = {#JoinColumn(name = "organization_id", referencedColumnName = "id", nullable = false)})
private Set<Organization> organizations= new HashSet<>();
#OneToOne(mappedBy ="user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#PrimaryKeyJoinColumn
#Setter(AccessLevel.NONE)
private UserRegister register;
#OneToMany(mappedBy ="tokenId.user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
private Set<SecureToken> tokens = new HashSet<>();
#OneToOne(mappedBy ="user", cascade = {CascadeType.REMOVE, CascadeType.MERGE, CascadeType.REFRESH}, fetch=FetchType.LAZY)
#PrimaryKeyJoinColumn
private UserLogin login;
//all the methods omitted from brevity
}
I create the Example matcher as follows:
UserAccount account= new UserAccount();
account.setUsername("John");
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
Example<UserAccount> regExample = Example.of(account, matcher);
List<UserAccount> out = repository.findAll(regExample);
Consider that a user with username "John" exists, but the output is always empty, no matter what parameter I fill.
Edit: this helps to find the solution: Are there any possible ways to ignore all paths of JPA Example Matcher. There is no way to automatically ignore primitive fields when not used?
Edit: Notice that I want to find all the UserAccount containing the specified strings in the selected fields. With other entities the configuration of ExampleMatcher works.

OSIV:false , cannot get session for resolving FetchType.Lazy items, even in the scope of #Transactional

In my spring application, I have disabled osiv (spring.jpa.open-in-view=false) to avoid holding hibernate sessions throughout a request lifecycle.
After disabling OSIV, I am getting the following error when I try to access a field in my entity that has the FetchType set as LAZY
org.hibernate.LazyInitializationException: could not initialize proxy [sg.identity.auth.entity.OrganizationEntity#2] - no Session
This is the entity I'm using and I'm trying to access userEntity.getOrganization() which results in the LazyInitializationException.
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "\"USER\"")
public class UserEntity extends AbstractAuditingEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#OneToOne(fetch = FetchType.LAZY)
#JoinTable(name = "organization_user",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "organization_id", referencedColumnName = "organization_id"))
private OrganizationEntity organization;
#ManyToMany(cascade = CascadeType.MERGE)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "user_parent_organization_unit_mapping",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "organization_unit_id", referencedColumnName = "organization_unit_id"))
private Set<OrganizationUnitEntity> organizationUnits;
#OneToOne(cascade = CascadeType.ALL)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "user_exclusion_mapping",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "excluding_permission_set_id", referencedColumnName = "permission_set_id"))
private PermissionSetEntity exclusionPermissions;
#ManyToMany(cascade = CascadeType.MERGE)
#org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#JoinTable(name = "user_role",
joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id", referencedColumnName = "role_id"))
private Set<RoleEntity> roles;
}
I'm calling the user.getOrganizationEntity in a method annotated with #Transactional so It should receive an open session to resolve the lazy items. But in my case, it is not working
#Transactional
public Organization getOrganization(String emailId) {
return userRepository.getUserByEmailId(emailId)
.map(UserEntity::getOrganization)
.map(OrganizationMapper::toDto)
.orElseThrow(() -> new IllegalArgumentException("error"));
}
The user.getOrganization is resolving correctly when I try using TransactionTemplate.
#Transactional
public Organization getOrganization(String emailId) {
return transactionTemplate.execute(status -> {
return userRepository.getUserByEmailId(emailId)
.map(UserEntity::getOrganization)
.map(OrganizationMapper::toDto)
.orElseThrow(() -> new IllegalArgumentException("error"));
});
}
I got it working with #Transactional itself by setting the property spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true, but from my research, i found that it is not recommended to set this flag as true

How to send POST request with Many to many relationship in Spring Boot

Anyone have any ideas on how I could do postmapping for the Many-to-Many relationship? Getting the data works, but this is what I'm having trouble with
I tried using the "guide" but unfortunately I don't understand it very well yet
Here is my entities:
Album
#Entity
public class Album implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
Long id;
String name;
String artist;
String cover;
#ManyToMany(fetch = FetchType.LAZY, cascade =
{
CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.REFRESH,
CascadeType.PERSIST
})
#JoinTable( name = "user_albums",
joinColumns = #JoinColumn(name = "album_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "user_id", nullable = false)
)
#JsonBackReference
#OnDelete(action = OnDeleteAction.CASCADE)
private Set<User> users = new HashSet<>();
User:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank
#Size(max = 20)
private String username;
#NotBlank
#Size(max = 50)
#Email
private String email;
#NotBlank
#Size(max = 120)
private String password;
#ManyToMany(fetch = FetchType.LAZY, cascade =
{
CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.REFRESH,
CascadeType.PERSIST
})
#JoinTable( name = "user_albums",
joinColumns = #JoinColumn(name = "user_id", nullable = false),
inverseJoinColumns = #JoinColumn(name = "album_id", nullable = false)
)
#OnDelete(action = OnDeleteAction.CASCADE)
private Set<Album> albums = new HashSet<>();
I tried it this way but it didn't work
#PostMapping("/users/mal/{userId}/album")
public ResponseEntity<Album> addAlbum(#PathVariable(value = "userId") Long userId, #RequestBody Album albumRequest, User userRequest) {
Album newMal = userRepo.findById(userId).map(user -> {
long albumId = userRequest.getId();
user.addAlbum(albumRequest);
return albumRepo.save(albumRequest);
}).orElseThrow(() -> new RuntimeException("Not found USER with id = " + userId));
return new ResponseEntity<>(newMal, HttpStatus.CREATED);

Hibernate model with multiple many-to-many relations slow performance when persisting

We have following schema as described on diagram below. There's an Entity with bidirectional many-to-many relations with two other entities(Relation1, Relation2). There's also many-to-many relation between Entity-Relation2 relationship itself and Relation1 entity. When we create an instance of Entity and persist into database, it's working fine, except that operation takes too much time. I'd like to ask, if there are any possible optimizations on Hibernate level, which could boost performance of save operation.
Here's diagram:
Model definitions:
class Entity : AbstractJpaPersistable() {
var name: String? = null
var description: String? = null
#OneToMany(mappedBy = "entity", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations1: List<EntityToRelation1> = emptyList()
#OneToMany(mappedBy = "entity", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations2: List<EntityToRelation2> = emptyList()
}
#Entity
class Relation2: AbstractJpaPersistable(){
#OneToMany(mappedBy = "relation2", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations2: List<EntityToRelation2> = emptyList()
}
#Entity
class Relation1: AbstractJpaPersistable(){
#OneToMany(mappedBy = "relation1", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations1: List<EntityToRelation1> = emptyList()
#OneToMany(mappedBy = "relation1", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations2Relations1: List<EntityToRelation2ToRelation1> = emptyList()
}
#Entity
class EntityToRelation2 {
#EmbeddedId
var entityToRelation2Id: EntityToRelation2Id = EntityToRelation2Id()
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("entityId")
#JoinColumn(name = "entity_id", insertable = false, updatable = false)
var entity: Entity? = null
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("relation2Id")
#JoinColumn(name = "relation2_id", insertable = false, updatable = false)
var relation2: Relation2? = null
#OneToMany(mappedBy = "entityToRelation2", fetch = FetchType.LAZY, cascade = [CascadeType.PERSIST], orphanRemoval = true)
var entityRelations2Relations1: List<EntityToRelation2ToRelation1> = emptyList()
}
#Embeddable
class EntityToRelation2Id : Serializable {
#Column(name = "entity_id")
var entityId: Int? = null
#Column(name = "relation2_id")
var relationId: Int? = null
}
#Entity
class EntityToRelation1 {
#EmbeddedId
var entityToRelation1Id = EntityToRelation1Id()
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("entityId")
#JoinColumn(name = "entity_id", insertable = false, updatable = false)
var entity: Entity? = null
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("relation1Id")
#JoinColumn(name = "relation1_id", insertable = false, updatable = false)
var relation1: Relation1? = null
}
#Embeddable
class EntityToRelation1Id : Serializable {
#Column(name = "entity_id")
var entityId: Int? = null
#Column(name = "relation1_id")
var relation1Id: Int? = null
}
#Entity
class EntityToRelation2ToRelation1 {
#EmbeddedId
var entityToRelation2ToRelation1Id = EntityToRelation2ToRelation1Id()
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("entityToRelation2Id")
#JoinColumns(
JoinColumn(name = "entity_id"),
JoinColumn(name = "relation2_id")
)
var entityToRelation2: EntityToRelation2? = null
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("relation1Id")
#JoinColumn(name = "relation1_id", insertable = false, updatable = false)
var relation1: Relation1? = null
}
#Embeddable
class EntityToRelation2ToRelation1Id : Serializable {
var entityToRelation2Id: EntityToRelation2Id? = null
#Column(name = "relation1_id")
var relation1Id: Int? = null
}

JPA Self Join using JoinTable

I have 1 entity call Item in which I want to be able to link parent items to children. to use a join table to create a parent/child relationship. I haven't been able to get any good documentation on. So if anyone has any thoughts I'm all ears.
Here is what I have... which works most of the time.
public class Item implements java.io.Serializable {
#Id
private Long id;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMTOITEM", joinColumns = { #JoinColumn(name = "ITEMID") }, inverseJoinColumns = { #JoinColumn(name = "PARENTITEMID") } )
private Item parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Item> children;
}
At times when I want to bring back objects that are tied to this item table I am getting an error of the following:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.webflow.engine.ActionExecutionException: Exception thrown executing [AnnotatedAction#6669ff5 targetAction = com.assisted.movein.web.common.nav.NavAction#6edf74b7, attributes = map['method' -> 'handleEntry']] in state 'oneTimeChargesAndFeesView' of flow 'in-flow' -- action execution attributes were 'map['method' -> 'handleEntry']'; nested exception is Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b04-fcs (04/11/2008))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-00904: "PARENTITEM_ITEMID": invalid identifier
Error Code: 904
Call: SELECT ITEMID, ITEMSHORTDESC, EFFENDDATE, ITEMDESC, PARENTITEM_ITEMID, ITEMTYPECODE FROM ITEM WHERE (ITEMID = ?)
bind => [1250]
Query: ReadObjectQuery(com.domain.Item)
Any help would be appreciated.
Try to use #JoinColumninstead:
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinColumn(name = "PARENTITEMID", referencedColumnName = "ITEMID")
private Item parent;
#OneToMany(
cascade = {CascadeType.ALL},
orphanRemoval = true,
fetch = FetchType.LAZY
)
#JoinColumn(name = "PARENTITEMID")
private List<Item> children;
After a lot of reading on JPA 2.0 I figured out that I needed a newer version of Eclipselink 2.3+ in order to support what I was trying to do. Here is the code that actually worked in my case, but it will not work due to our dependency on an older version [EclipseLink 2.0.2]. Also another project's is still using Toplink-essentials JPA 1.0 which again does like this notation.
public class Item {
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID", insertable = false, updatable = false) } )
private Item parentItem;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name = "ITEMINCENTIVESMAPPING",
joinColumns = { #JoinColumn(name = "INCENTIVEITEMID", referencedColumnName = "ITEMID") },
inverseJoinColumns = { #JoinColumn(name = "ITEMID", referencedColumnName = "ITEMID") } )
private List<Item> items;
}
I believe #JoinTable is only allowed on a #OneToOne or #OneToMany or #ManyToMany, I don't think it makes any sense on a #ManyToOne. Use a #JoinColumn, or a #OneToOne.
Also your #OneToMany does not make sense, the mappedBy must be an attribute and you have no parentItem, it should be parent, and parent should use a #JoinColumn.

Resources