is there a #MappedSuperclass equivalent annotation for mongoDB in spring? - java

In my project, we are moving from SQL to NoSQL to a certain extent.
I wanted to know, how can we inherit BaseClass properties into child classes in spring data mongo.
I know how to do it in Spring JPA for SQL.
Example,
Below is BaseEntity parent class which is annotated with #MappedSuperClass
It has id and version as its fields.
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue
private Long id;
#Version
private Integer version;
//Getters and setters omitted for brevity
}
entities can extend the BaseEntity class and skip declaring the #Id or #Version properties since they are inherited from the base class.
#Entity(name = "Post")
#Table(name = "post")
public class Post extends BaseEntity {
private String title;
#OneToMany
private List comments = new ArrayList();
#OneToOne
private PostDetails details;
#ManyToMany
#JoinTable(//Some join table)
private Set tags = new HashSet();
//Getters and setters omitted for brevity
public void addComment(PostComment comment) {
comments.add(comment);
comment.setPost(this);
}
public void addDetails(PostDetails details) {
this.details = details;
details.setPost(this);
}
public void removeDetails() {
this.details.setPost(null);
this.details = null;
}
}
#Entity(name = "PostComment")
#Table(name = "post_comment")
public class PostComment extends BaseEntity {
#ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
}
How can I implement same thing in Mongo? For example
#MappedSuperclass
public class BaseEntity {
#Id
#GeneratedValue
private Long id;
#Version
private Integer version;
//Getters and setters omitted for brevity
}
#Document(collection = "Post")
public class Post extends BaseEntity {
private String title;
//Rest of the code
}
#Document(collection = "PostComment")
public class PostComment extends BaseEntity {
#ManyToOne(fetch = FetchType.LAZY)
private Post post;
private String review;
//Getters and setters omitted for brevity
}

You do not need any annotation to do that in Mongo. Mongo itself will take care of superclass for you.
Just extend BaseEntity class in all your entities, all entities will have fields from BaseEntity class when you read and write entities to database. This also works at multilevel hierarchy. i.e. Post extends BaseEntity, BaseEntity extends Entity, in this case Post will have fields from both BaseEntity and Entity class.

Related

Is there a way to generate #Entity classes based on existing classes?

I have somewhat big object model in my app, and want to decouple model definition from persistence layer. This is an example of class that I want to generate entity class from:
#Setter
#Getter
public abstract class AbstractAccount {
protected Long id;
protected AbstractProfile profile;
protected AbstractAuthorization<AbstractRole> authorization;
protected AbstractWallet wallet;
protected AbstractActivityHistory<AbstractGameSessionRecord, AbstractOperationRecord> history;
// Constructors and stuff...
}
Simply marking every class with #Entity, manipulating field annotations as well would be enough, but I really need to decouple them. I want to get entities like this:
#Data
#Entity
#SuperBuilder
#Inheritance(strategy = InheritanceType.JOINED)
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public abstract class AccountEntity {
public AccountEntity(AccountType accountType) {
this.accountType = accountType;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long id;
#Embedded
public AbstractWalletEntity walletEntity;
#Embedded
public AbstractProfileEntity profileEntity;
#Embedded
AbstractAuthorizationEntity authorizationEntity;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
public AccountType accountType;
}

Hibernate embed a mapped superclass

I am trying to use #ElementCollection with a set of classes which are all inherited from a #MappedSuperclass but when persisting to the database there is no column to identify which subclass was created and therefore will fail when trying to retrieve it from the database. If I change the class to make it an entity instead it will then work but I need it to be #Embeddable to work with #ElementCollection
Below is the code:
#Entity
public class A {
private String attr1;
private String attr2;
....
#ElementCollection
private List<B> list;
....
}
Superclass:
#Embeddable
#MappedSuperclass
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class B {
private String attr3
private String attr4
....
}
Subclass1:
#Embeddable
#DiscriminatorValue("B1")
public class B1 extends B {
private String attr5
....
}
Subclass2:
#Embeddable
#DiscriminatorValue("B2")
public class B2 extends B {
private String attr6
....
}
Thanks in advance
#ElementCollection is for basic or embeddable values which both have no concept of inheritance. If you want inheritance, you need to model the value as entity and then use #OneToMany. From a relational mapping perspective, the two mappings are almost the same:
#Entity
public class A {
private String attr1;
private String attr2;
....
#OneToMany(mappedBy = "a")
private List<B> list;
....
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class B {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "a_id")
private A a;
private String attr3
private String attr4
....
}

Java and Hibernate - How to make OneToOne relation with SuperMappedClass and not an Entity

I have tree Entities: Client, ClientConfigurationA and ClientConfigurationB.
I try to make something like:
#Entity
#Table(name = "CLIENT")
public class Client {
#Id
private int id;
#OneToOne(mappedBy = "client")
private ClientConfiguration configuration
// some getter and setter
}
#MappedSuperClass
public class ClientConfiguration {
#Id
private int id;
#OneToOne
#MapsId
protected Client client;
// getters and setters
}
#Entity(name = "CLIENT_CONF_A")
public class ClientConfigurationA extends ClientConfiguration { ... }
#Entity(name = "CLIENT_CONF_B")
public class ClientConfigurationB extends ClientConfiguration { ... }
But actually I can't define a OneToOne related to MappedSuperClass and not an Entity.
So what's the best way to implement this case ?
I already tried this solution without succes.
Thanks for reading.
It's impossible and here's why:
When hibernate processes entities it needs to know what table to join with when resolving one to one relations.
The problem arise with #MappedSuperClass is that it doesn't define table, so multiple entities could be inherited from this class, each one having different table. Hibernate just couldn't know what table to join then.
If you want to have common super class, I suggest using an abstract #Entity class.
After many attempts i finally succeeded.
#Entity
#Table(name = "CLIENT")
public class Client {
#Id
private int id;
#OneToOne(mappedBy = "client")
private ClientConfiguration configuration
// some getter and setter
}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#DiscriminatorColumn(name = "TYPE")
public abstract class ClientConfiguration {
#Id
private int id;
#Column(name = "TYPE")
private String type;
#OneToOne
#MapsId
protected Client client;
// getters and setters
}
#Entity(name = "CLIENT_CONF_A")
public class ClientConfigurationA extends ClientConfiguration { ... }
#Entity(name = "CLIENT_CONF_B")
public class ClientConfigurationB extends ClientConfiguration { ... }

Spring data Repositiry does not check for isNew(entity) on classes that are marked to be cascaded under the main entity

I have a parent class (for ease of understanding and running on your locals i have simplified the class structure)
#Entity
#Table(name = "entity_a")
public class EntityA implements Serializable, Persistable<Integer> {
#Id
#Column(name = "id")
private Integer id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "entity_b_id")
private EntityB entityB;
/* Getter and Setter */
#Override
public boolean isNew() {
return isNew;
}
}
#Entity
#Table(name = "entity_b")
public class EntityB implements Serializable, Persistable<String> {
#Id
#Column(name = "id")
private String id;
#Column(name = "name")
private String name;
#OneToOne(mappedBy = "entityB")
private EntityA entityA;
/* Getters and Setters */
#Override
public boolean isNew() {
return isNew;
}
}
When I try to persist the new entity EntityA using the following spring data repository:
public interface EntityARepository extends JpaRepository<EntityA, Integer> {
}
it only checks for isNew on EntityA but ignores the isNew on EntityB and I keep getting primary key constraint errors on the persist operation
The reason why I am implementing the Persistable interface is because the EntityB is actually something that can be repeated quite a few times so I would like to check for its existence and set the isNew boolean accordingly before its saved
How do I make the spring repository take into account the isNew property of the child class as well that is marked to be cascaded

Composite Key with subclass in hibernate

I have a Class system
#Entity
abstract class System{
#Id
int systemId;
//setter and getters..
}
and which is extended by class
#Entity
class PhysicalSystem extends System
{
#Id
int place;
//setter and getters..
}
in need to make the composite key by using the systemId and place
how can i do this.. if i have #Id in both class its throws exception
Initial SessionFactory creation failed.java.lang.ClassCastException: org.hibernate.mapping.JoinedSubclass cannot be cast to org.hibernate.mapping.RootClass
How can i solve this?
Tables:
System{
systemid PK
systemName
}
PhysicalSystem
{
systemId PK
locationId PK
}
In your case, maybe the best solution is a OneToOne mapping:
#Entity
public class PhysicalSystem implements Serializable {
#EmbeddedId
private PhysicalSystemKey key;
#JoinColumns({JoinColumn(name = "key.systemId", referencedColumnName = "ctvId"})
#OneToOne(mappedBy = "physicalSystem")
private System system;
// ...
}
#Embeddable
public class PhysicalSystemKey {
private Long systemId;
private Long locationId;
// ...
}
#Entity
public class System implements Serializable {
#Id
private Long systemId;
#OneToOne(mappedBy = "system")
private PhysicalSystem physicalSystem;
}

Categories