how to model a singleton object to table through hibernate? - java

I have a global config object in my project and there can ever be 0 or 1 instance of this class that i want to persist in db. What is the best way to do this ? One trick i know here is to have a "constant" field mapped with unique constraint set on it, are there other such ways as this looks a little hacky ?
Here's what i tried :-
#Entity
public class DTLdapConfig implements Serializable {
#GeneratedValue(strategy=GenerationType.TABLE)
#Id
private int id;
#Column(unique=true)
private boolean singletonGuard;
// no public setter getter for singletonGuard
// other code below
}

Related

Spring data repository findById vs derived findBy[id-column-name]

Let's say we have an entity class with the following id:
#Entity
class SomeEntity {
#Id
private String key;
...
}
Is there any difference between using CrudRepository's findById(key) and using our own method findByKey(String key)?
And is there any difference between both when the primary key is composite, e.g:
class CompositeKey implements Serializable {
private Integer firstKey;
private String secondKey;
...
}
#Entity
#IdClass(CompositeKey.class)
class SomeEntity {
#Id
private Integer firstKey;
#Id
private String secondKey;
...
}
and then
findById(new CompositeKey(...)) vs findByFirstKeyAndSecondKey(int firstKey, String secondKey) ?
Yes there is a difference.
findById is implemented by using a dedicated method on the EntityManager which will check the 1st level cache first and therefore potentially avoids any database access.
The derived query method will create a query and execute it as long as you don't have a query cache configured.
If the entity in question isn't in the 1st level cache the code path executed is still significantly different, but it is unlikely that you'll notice it in production.

Using Java records as JPA embeddables

I want to use Java records as embeddable objects with JPA. For example I want to wrap the ID in a record to make it typesafe:
#Entity
public class DemoEntity {
#EmbeddedId
private Id id = new Id(UUID.randomUUID());
#Embeddable
public static record Id(#Basic UUID value) implements Serializable {}
}
But If I try to persist it with Hibernate 5.4.32 I get the following error:
org.hibernate.InstantiationException: No default constructor for entity: : com.example.demo.DemoEntity$Id
at org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:85) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
at org.hibernate.tuple.component.AbstractComponentTuplizer.instantiate(AbstractComponentTuplizer.java:84) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
...
So it looks like Hibernate would treat the record Id like an entity, although it is an #Embeddable.
The same happens with non-id fields and #Embedded:
#Embedded
private Thing thing = new Thing("example");
#Embeddable
public static record Thing(#Basic String value) implements Serializable {}
Is there a way to use #Embeddable records with JPA/Hibernate?
Java records with a single field can be used for custom ID types or any other value object with AttributeConverters.
In the entity class the ID type is used with #Id as usual:
#Entity
public class DemoEntity {
#Id
private Id id = new Id(UUID.randomUUID());
public static record Id(UUID value) implements Serializable {}
}
Note that the record Id doesn't have any annotation.
The converter makes it possible to use records:
#Converter(autoApply = true)
public class DemoEntityIdConverter implements AttributeConverter<DemoEntity.Id, String> {
#Override
public String convertToDatabaseColumn(DemoEntity.Id id) {
return id.value().toString();
}
#Override
public DemoEntity.Id convertToEntityAttribute(String s) {
return new DemoEntity.Id(UUID.fromString(s));
}
}
Don't forget to set autoApply = true to have this converter applied automatically (without referencing it explicitly on the respective field).
Records with more than one field could be mapped with a Hibernate UserType, but that is a bit cumbersome.
Entity or embeddable, in any case the record class wouldn't be suitable here because entities and their fields, including embeddable ones, are modifiable. The only exception would be for Id fields, but that doesn't seem like an important enough case to make this functionality for.
One of the Hibernate developers explains this here

Persist functor in a realtional database

I have a Java Entity that has several well defined functors. I want to persist them so as not factorize the object once it is fetched from the database. Is there a way to do so with Ebean?
I think that I could get it saving the class name that implements those functors as a String in the entity and in the setter of that string implement the setter of the functor with Reflection. Any other idea?
Class Example:
#Entity
public Foo extends Model
{
#Id
private Long id;
#Transient
private Runnable functor;
private String classFunctor;
public void setClassFunctor(String value)
{
//Here I implement the Reflection routine to load the functor.
}
}

How annotation mapping is done in java persistence?

We use annotations for mapping the entity class with the database table by simply specifying #Entity and more like #Id, table joins and many things. I do not know how these entity variables are getting mapped with database table. Can anyone give a short description for understanding.
Thanks :)
Well the idea is to translate your objects and their connections with other objects into a relational database. These two ways of representing data (objects defined by classes and in tables in a database) are not directly compatible and that is where a so called Object Relational Mapper framework comes into play.
So a class like
class MyObject
{
private String name;
private int age;
private String password;
// Getters and setters
}
Will translate into a database table containing a column name which is of type varchar, age of type int and password of type varchar.
Annotations in Java simply add additional information (so called meta data) to your class definitions, which can be read by any other class (e.g. JavaDoc) and in the case of the Java Persistence API will be used by an ORM framework like Hibernate to read additional information you need to translate your object into the database (your database table needs a primary id and some information - like what type of a relation an object has to another - can't be automatically determined by just looking at your class definition).
Annotations are very well explained here:
http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/
annotations are just metadata on a class, nothing magical. You can write your own annotations. Those annotations are given retention policies of runtime (which means you have access to that metadata at runtime). When you call persist etc the persistence provider iterates through the fields (java.lang.reflect.Field) in your class and checks what annotations are present to build up your SQL statement. Try writing your own annotation and doing something with it. It won't seem very magical after that.
in your case annotation working means mapping with tablename with entity class is look like as ....
#Entity
#Table(name = "CompanyUser")
public class CompanyUserCAB implements java.io.Serializable
{
private long companyUserID;
private int companyID;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "companyUserID")
public long getCompanyUserID()
{
return this.companyUserID;
}
public void setCompanyUserID(long companyUserID)
{
this.companyUserID = companyUserID;
}
#Column(name = "companyID")
public int getCompanyID()
{
return this.companyID;
}
public void setCompanyID(int companyID)
{
this.companyID = companyID;
}
}

Problem persisting inheritance tree

I have a problem trying to map an inheritance tree. A simplified version of my model is like this:
#MappedSuperclass
#Embeddable
public class BaseEmbedded implements Serializable {
#Column(name="BE_FIELD")
private String beField;
// Getters and setters follow
}
#MappedSuperclass
#Embeddable
public class DerivedEmbedded extends BaseEmbedded {
#Column(name="DE_FIELD")
private String deField;
// Getters and setters follow
}
#MappedSuperclass
public abstract class BaseClass implements Serializable {
#Embedded
protected BaseEmbedded embedded;
public BaseClass() {
this.embedded = new BaseEmbedded();
}
// Getters and setters follow
}
#Entity
#Table(name="MYTABLE")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="TYPE", discriminatorType=DiscriminatorType.STRING)
public class DerivedClass extends BaseClass {
#Id
#Column(name="ID", nullable=false)
private Long id;
#Column(name="TYPE", nullable=false, insertable=false, updatable=false)
private String type;
public DerivedClass() {
this.embedded = new DerivedClass();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Embeddable
public static NestedClassA extends DerivedEmbedded {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
}
public DerivedClassA() {
this.embedded = new NestedClassA();
}
// Getters and setters follow
}
#Entity
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Embeddable
public static NestedClassB extends DerivedEmbedded {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
}
public DerivedClassB() {
this.embedded = new NestedClassB();
}
// Getters and setters follow
}
At Java level, this model is working fine, and I believe is the appropriate one. My problem comes up when it's time to persist an object.
At runtime, I can create an object which could be an instance of DerivedClass, DerivedClassA or DerivedClassB. As you can see, each one of the derived classes introduces a new field which only makes sense for that specific derived class. All the classes share the same physical table in the database. If I persist an object of type DerivedClass, I expect fields BE_FIELD, DE_FIELD, ID and TYPE to be persisted with their values and the remaining fields to be null. If I persist an object of type DerivedClass A, I expect those same fields plus the FIELD_CLASS_A field to be persisted with their values and field FIELD_CLASS_B to be null. Something equivalent for an object of type DerivedClassB.
Since the #Embedded annotation is at the BaseClass only, Hibernate is only persisting the fields up to that level in the tree. I don't know how to tell Hibernate that I want to persist up to the appropriate level in the tree, depending on the actual type of the embedded property.
I cannot have another #Embedded property in the subclasses since this would duplicate data that is already present in the superclass and would also break the Java model.
I cannot declare the embedded property to be of a more specific type either, since it's only at runtime when the actual object is created and I don't have a single branch in the hierarchy.
Is it possible to solve my problem? Or should I resignate myself to accept that there is no way to persist the Java model as it is?
Any help will be greatly appreciated.
Wow. This is the simplified version? I assume that the behavior that you are seeing is that BaseEmbedded field is persisted but not the FIELD_CLASS_A or B?
The problem is that when Hibernate maps the DerivedClassA and B classes, it reflects and sees the embedded field as a BaseEmbedded class. Just because you then persist an object with the embedded field being a NestedClass, the mapping has already been done and the FIELD_CLASS_A and B are never referenced.
What you need to do is to get rid of the NestedClass* and embedded field and instead have the fieldClassA and B be normal members of DerivedClassA and B. Then add add a name field to the #Entity which will put them both in the same table I believe. This will allow you to collapse/simplify your class hierarchy a lot further.
See: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e1168
#Entity(name = "DerivedClass")
#DiscriminatorValue("A")
public class DerivedClassA extends DerivedClass {
#Column(name="FIELD_CLASS_A")
private String fieldClassA;
...
#Entity(name = "DerivedClass")
#DiscriminatorValue("B")
public class DerivedClassB extends DerivedClass {
#Column(name="FIELD_CLASS_B")
private String fieldClassB;
...

Categories

Resources