I want to use Hibernate. I have a database schema and I would like to write annotations in my code.
I have az A class. It's look like this:
In A.java:
public class A {
public Integer id;
}
In B.java:
#Entity
#Table(name="table_b")
public class B extends A {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
//How can I get that id attribute from the A class?
#Column
public String string;
}
you put the annotation #MappedSuperClass above class A. The field id has to be annotated in clas A not B.
Related
I have this generic entity:
#MappedSuperclass
abstract class Position<T> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Enumerated(EnumType.STRING)
private T name;
}
But there's a case where the generic type is a String:
#Entity
class ChildPosition0 extends Position<String> {
}
And, JPA will complaint that String is not an enum in this case, but I need to annotate this name field if it's an enum, if not, the database will mark it as int type, and that's not ideal. How do I solve this? How to annotate the field conditionally?
My workaround:
Use Position as a parent class, and adding those field in child class individually, even though they share the same field:
#MappedSuperclass
abstract class Position {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
And extends it from child entity like this:
Child1:
#Entity
public class ChildPosition1 extends Position {
#Enumerated(EnumType.STRING)
private Priority name; // <- Priority is enum type
}
Child2:
#Entity
public class ChildPosition2 extends Position {
private String name;
}
This is too ugly IMO. And Java does not allow class field override from child class. So, back to the question: how to annotate generic field conditionally?
I have a simple base class in which I want to have some common fields, like id etc. The base class is not an Entity by itself.
public class Base {
#Id
protected long id;
protected String someOtherCommonProperty;
}
And I have an entity class, extending the base class.
#Entity
public class Entity extends Base {
String name;
String address;
}
I would expect the entity class to inherit the fields from the base class, but what I get is
[ObjectBox] No #Id property found for 'Entity', add #Id on a not-null long property.
Is there any way to fix that, besides using interfaces and have a lot of duplicated code?
You can use the #BaseEntity annotation.
Have a look at the documentation: Objectbox - Entity Inheritence.
Shameless copy for future reference:
In addition to the #Entity annotation, we introduced a #BaseEntity annotation for base classes, which can be used instead of #Entity.
There three types of base classes, which are defined via annotations:
No annotation: The base class and its properties are not considered for persistence.
#BaseEntity: Properties are considered for persistence in sub classes, but the base class itself cannot be persisted.
#Entity: Properties are considered for persistence in sub classes, and the base class itself is a normally persisted entity.
Example:
// base class:
#BaseEntity
public abstract class Base {
#Id long id;
String baseString;
public Base() {
}
public Base(long id, String baseString) {
this.id = id;
this.baseString = baseString;
}
}
// sub class:
#Entity
public class Sub extends Base {
String subString;
public Sub() {
}
public Sub(long id, String baseString, String subString) {
super(id, baseString);
this.subString = subString;
}
}
How can I tell hibernate to ignore a field during schema auto generation?
In this special case: the field is inherited from a parent abstract class, so I cannot just comment it out!
I tried using #Transient, but the field is still autogenerated in the schema.
#MappedSuperclass
public abstract class BaseEntity {
private String someField;
//getter+setter
}
#Entity
public class MyEntity extends BaseEntity {
#Transient //I want to ignore this field during hibernate.ddl.auto
#Override
public String getSomeField() {}
}
Add the Transient annotation in the super class:
#MappedSuperclass
public abstract class BaseEntity {
#Transient
private String someField;
}
#Entity
public class MyEntity extends BaseEntity {
}
For reasons that were around before I got to this project, there are tables that are similar types but have different ID columns.
So, when I try this
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Element implements Serializable {
public String title;
}
#Entity
public class PrimaryElement extends Element {
#Id
long pid;
}
#Entity
public class OtherElement extends Element {
#Id
long oid;
}
But then I get an obvious error
No identifier specified for entity: Element
Now, I can't very well put the ID in the Element class because they are obviously mapped to different columns.
I have tried various flavors of #Id and 'abstract' and #MappedSuperClass and so on..
I am at a complete loss. Is there a way around this?
Any insights would be appreciated.
Thanks!
You can either replace the #Entity and #Inheritance annotations of your Element class by #MappedSuperclass (this annotation is responsible for technical mappings and only PrimaryElement and OtherElement will be fully featured entities) or move the oid field with it's #Id annotation to the class Element and use the #AttributeOverride annotation in it's subclasses to modify the column names (in this case also the abstract class Element will be a fully featured entity).
#AttributeOverride(name="oid", column=#Column(name="primary_element_id"))
UPDATE:
#MappedSuperclass
public abstract class Element implements Serializable {
#Id
private long id;
public String title;
}
#Entity
#AttributeOverride(name="id", column=#Column(name="pid"))
public class PrimaryElement extends Element {
}
#Entity
#AttributeOverride(name="id", column=#Column(name="oid"))
public class OtherElement extends Element {
}
I have two hibernate classes: a base class, and an extended class that has additional fields. (These fields are mapped by other tables.)
For example, I have:
#Entity
#Table(name="Book")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
public class B extends A {
public String node_ID;
// ...
}
public class Node {
public String ID; // maps to B.node_ID
// ...
}
How do I map this in Hibernate? The hibernate documentation states three types of inheritence configurations: one table per class, one table with a type column, and a join table -- none of which apply here.
The reason I need to do this is because class A is from generic framework that's reused over multiple projects, and class B (and Node) are extensions specific to one project -- they won't be used again. In the future, I may have perhaps a class C with a house_ID or some other field.
Edit: If I try the above pseudo-code configuration (two entities mapped to the same table) I get an error that the DTYPE column doesn't exist. The HQL has a "where DTYPE="A" appended.
This is possible by mapping the #DiscriminatorColumn and #DiscriminatorValue to the same values for both classes; this can be from any column you use that has the same data regardless of which type (not sure if it works with null values).
The classes should look like so:
#Entity
#Table(name="Book")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="published")
#DiscriminatorValue(value="true")
public class A {
private String ID;
private String Name;
// ...
}
#Entity
#Table(name="Book")
#DiscriminatorValue(value="true")
public class B extends A {
public String node_ID;
// ...
}
For anyone who got here like me and does not want to have the dtype column but instead want to use the same table for more than one entity as is I would recommend using this
Basically you can create a Base like this
#MappedSuperclass
public abstract class BaseBook<T extends BaseBook> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private Long id;
... any other variables, getters + setters
}
#Entity
#Table(name= "book")
public class BookA extends BaseBook<BookA>{
//Default class no need to specify any variables or getters/setters
}
#Entity
#Table(name= "book")
public class BookB extends BaseBook<BookB>{
#Column(name = "other_field")
private String otherFieldInTableButNotMapedInBase
... Any other fields, getter/setter
}
From the above we have created base super class which does not have any entity or table mapping. We then create BookA to be default with the Entity + Table mapping. From there we can create other Entities all extending from BaseBook but pointing to one table