How to init array property of annotation in Kotlin - kotlin

#Entity
#Table(name = "t_payment")
data class PaymentEntity(
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "user_id", nullable = false)
var user: User? = null) : Serializable {
}
as a result of a compilation error: "Type mismatch"

cascade annotation attribute accepts an array of CascadeType thus you need to change your #ManyToOne usage to:
#ManyToOne(cascade = arrayOf(javax.persistence.CascadeType.DETACH))

Related

How to access the join column (Foreign key) in Spring Data JPA without loading the mapped entity

I have a POST entiry and HeadingSlugEntity.
public class PostEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String postId;
private String uid;
private String dateCreated;
private String dateUpdated;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "headingSlugId", referencedColumnName = "headingSlugId")
private HeadingSlugEntity headingSlugEntity;
}
I have a 1:1 mapping for HeadingSlugEntity. When I save post entity and headingSlugEntity together, headingSlugId is getting auto-populated. That is working fine.
The next time when I fetch the post entity, I need to access the headingSlugId without getting the headingSlugEntity. (At this point of time, I don't need HeadingSlugEntity, I just need its ID.) I just need to get the headingSlugId. How to do it.
Since this entity is not having the field headingSlugId, I can't set and get it. If I add a field named headingSlugId inside post entity, I will get hibernate duplicate field error. If I put
insertable = false, updatable = false)
and add field headingSlugId, the headingSlugId will be Null.
What basic stuff I am missing here ?
You can map the foreign key to the entity twice in this case, one for actual ORM and another for getting the FK without actually firing a new query.
public class Answer {
#Column(name = "headingSlugId", insertable = false, updatable = false)
private Integer headingSlugId;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "headingSlugId", referencedColumnName = "headingSlugId")
private HeadingSlugEntity headingSlugEntity;
}

Spring Data REST - how to create an object with relationships in one request?

#Entity
#Table(name = "distributor")
class Distributor : AbstractEntity<Long>() {
#Column(nullable = false)
val name: String? = null
#OneToMany(mappedBy = "distributor", cascade = [CascadeType.ALL])
#RestResource
var managers: MutableList<DistributionManager>? = null
#OneToMany(mappedBy = "distributor")
var catalog: MutableList<Good> = mutableListOf()
}
#Entity
#Table(name = "distribution_manager")
class DistributionManager : AbstractPersonEntity<Long>() {
#ManyToOne
#JoinColumn(name = "distributor_id")
var distributor: Distributor? = null
}
What request i need do for creating 'Distributor' entity with relationship 'DistributionManager' in one request?
So far I have found a way to do this in 3 requests:
Create a 'Distributor'
Create a 'DistributionManager'
Create a relation
But it's kind of cumbersome

Cant get hibernate to update object without EntityExistException being thrown

I am trying to do a bidirectional one to one relation and when updating the AccountExtrasModel on the first save it works fine but when updating I get either an error or the sql statements adds an insert and then a delete instead of an update.
import lombok.*;
import javax.persistence.*;
#ToString
#NoArgsConstructor
#Getter
#Setter
#Entity
#Table(name = "Account")
public class AccountModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long Account_ID;
#Column(nullable = false, updatable = false)
private String name;
#Column(nullable = false, unique = true, updatable = false)
private String email;
#Column(nullable = false, updatable = false)
private String password;
#OneToOne(mappedBy = "accountModel", cascade = CascadeType.ALL, orphanRemoval = true)
private AccountExtrasModel accountExtras;
public AccountModel addExtras(AccountExtrasModel accountExtrasModel) {
accountExtrasModel.setAccountModel(this);
this.setAccountExtras(accountExtrasModel);
return this;
}
}
import lombok.*;
import javax.persistence.*;
#Setter
#Getter
#NoArgsConstructor
#ToString
#Entity
#Table(name = "AccountExtras")
public class AccountExtrasModel {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long ID;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private AccountModel accountModel;
#Lob
private String description;
private String[] myVideos;
private String[] likedVideos;
private String imageReference;
}
If i change the #MapsId to #JoinColumn in AccountExtrasModel then i get the desired result but what its doing is inserting a new row and linking it to acccount and then deleting the old row instead of doing an update.
This is the error im getting:
{
"timestamp": "2018-04-26T18:19:01.657+0000",
"status": 500,
"error": "Internal Server Error",
"message": "A different object with the same identifier value was already associated with the session : [com.alttube.account.models.AccountExtrasModel#1]; nested exception is javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.alttube.account.models.AccountExtrasModel#1]",
"path": "/update_account"
}
What can i do to get the desired result which is to simply perform an update on the accountExtrasModel to the corresponding account to which it belongs?
If you update an AccountModel instance by setting a new instance of AccountExtrasModel, as you do in addExtras(), then it is normal to have a delete+insert. By updating the id you would end with orphaned records.
When you set new values on AccountExtrasModel instance, check if accountExtras is initialized. If not, do the addExtras() stuff. If it is, do not replace it, just change it, so hibernate will generate an update on the extras table (but keep the record id unchanged).
Instead of use the method save try use the method merge, because in case of object exist in database the framework will update this object.
Case the object don't exist, the framework will insert as normal.
Regards!

Filter elements of fetched collection. EclipseLInk. Criteria API

I have an object:
#Entity
#Table(name = "users", catalog = "adm", uniqueConstraints = #UniqueConstraint(columnNames = "loginUser"))
public class User implements GenericEntityPK<Integer> {
private Set<Permission> permissions = new HashSet<Permission>(0);
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "user_l_permission", catalog = "adm", joinColumns = {
#JoinColumn(name = "idUser", nullable = false, updatable = false) }, inverseJoinColumns = {
#JoinColumn(name = "idPermission", nullable = false, updatable = false) })
public Set<Permission> getPermissions() {
return this.permissions;
}
}
I want to select user entity and fetch collection of permissions, with where clause. In other words permissions collection must contain only elements that satisfy where conditions.
I've tried to do it with SetJoin but with no success..
Is there a way to do it?
I would recommend you instead query for the permissions that match the user and filter you want when needed. You can even cache this collection in your entity with a transient collection to pass it around in the object. Using filters on relationships ends up causing problems and corrupts the cache as what is in the object is no longer a true representation of what is in the database.
That said, there is no JPA way to do it, but Eclipselink supports additional criteria

JPA #ElementCollection generates strange unique key

I have an entity class PositionOrdering which contains an element collection:
#ElementCollection(targetClass = Position.class, fetch = FetchType.EAGER)
#CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = #JoinColumn(name = "position_ordering_id"))
#OrderColumn
List<Position> positions = new ArrayList<>();
When hibernate generates the database structure, it looks like this:
CREATE TABLE wls.position_ordering_position
(
position_ordering_id bigint NOT NULL,
positions_id bigint NOT NULL,
positions_order integer NOT NULL,
...
}
It's ok and exactly what I was expected. But it also generate a unique contsraint on positions_id column. It is strange, because the position id should be unique only per ordering, so any of the following unique keys would be ok:
position_ordering_id + positions_order
position_ordering_id + positions_id
But not on the single column of positions_id.
Because the constraint is generated automatically, I can't ignore or remove it simply.
Can I configure my collection to create correct unique constraint or at least not to create any?
UPDATE:
As for request, here is the skeleton of the Position entity:
#Entity
#SequenceGenerator(name = EntityBase.SEQUENCE_NAME,
sequenceName = "POSITION_ID_SEQ")
#Table(name = "position")
public class Position extends EntityBase {
// Lots of fields, like row, column number, and type, etc.
}
Where EntityBase is a simple class with some utility function and with Id:
#MappedSuperclass
public abstract class EntityBase implements Serializable, Cloneable {
public static final String SEQUENCE_NAME = "SEQUENCE_GENERATOR";
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = SEQUENCE_NAME)
protected Long id;
//..
}
#ElementCollection is used for mapping basic types or #Embedded classes, not entities. From the documentation
An ElementCollection can be used to define a one-to-many relationship to an Embeddable object, or a Basic value (such as a collection of Strings).
Since Position is an #Entity, you should map it as #OneToMany or #ManyToMany. I don't know the exact reason why are you getting that unique key generated, but I guess you can expect unpredictable results if you use the annottion in a was that it was not intended for.
As Predrag Maric described it in the accepted answer, the problem was that Position was not an `Embeddable'. My solution was:
I created a support class which wraps the Position into an #Embeddable entity:
#Embeddable
//#Table(name = "position_ordering_position")
public class PositionOrderingPosition {
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "position_id", nullable = false)
private Position position;
public PositionOrderingPosition() {
}
public PositionOrderingPosition(Position position) {
this.position = position;
}
public Position getPosition() {
return position;
}
}
Also I changed the Element collection to this:
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "POSITION_ORDERING_POSITION",
joinColumns = #JoinColumn(name = "position_ordering_id"))
#OrderColumn
List<PositionOrderingPosition> positions = new ArrayList<>();
Now it creates the same table, but with the right constraints.