JPA Entity Inheritance and UniqueConstraint with DiscriminatorColumn - java

Im using Hibernate with JPA 2.1 and I want to define an entity with two sub entities. My problem is that I want to define an UniqueConstraint with two columns: One MemberField and the DiscriminatorColumn.
EDIT: Because the answer of Nicholas solved my specific problem I changed the type of the parent class from abstract to non-abstract.
My code looks like this:
Parent
#Entity
#Inheritance
#DiscriminatorColumn(name = "TYPE")
#Table(name = "EXAMPLE", uniqueConstraints = #UniqueConstraint(columnNames = { "TYPE", "NAME" }) )
public class ExampleParent extends AbstractEntity
{
private static final long serialVersionUID = 68642569598915089L;
#Column(name = "NAME", nullable = false, length = 30)
#NotNull
private String name;
...
}
Child 1
#Entity
#DiscriminatorValue("TYPE1")
public class Example1 extends ExampleParent
{
private static final long serialVersionUID = -7343475904198640674L;
...
}
Child 2
#Entity
#DiscriminatorValue("TYPE2")
public class Example2 extends ExampleParent
{
private static final long serialVersionUID = 9077103283650704993L;
...
}
Now I don't want a UniqueConstraint on the name of the ExampleParent, because I want to be able to persist two objects of Example1 and Example2 with the same name. The following code should explain it:
#Autowired
Example1Repository example1Repo;
#Autowired
Example2Repository example2Repo;
Example1 example1 = new Example1();
example1.setName("example");
example1Repo.save(example1);
Example2 example2 = new Example2();
example2.setName("example");
example2Repo.save(example2);
So my goal is to set a UniqueConstraint of two columns but I actually want to use the DiscriminatorColumn and a field of my ExampleParent. The combination of the DiscriminatorColumn and the name should be unique.
My code doesn't work, so what are my options?

If you are using an abstract base class I would expect that you would be using a #MappedSuperclass annotation instead of #Inheritance.
#MappedSuperclass is better for polymorphism, which is what you have. I don't think that #Inheritence supports polymorphism.

Related

can two Java Entities that have "Has a" relationship use the same table

I have two tables A and B:
#Entity
public class A {
}
#Entity
public class B {
private final A a;
private String someBSpecificField;
}
Entity A is already Coded nicely and mapped to an existing table. My job is to create B and for some reason I prefer composition over inheritance between A and B. At the same time I want to have single table for A and B to avoid joins when reading. Can I do like this:
#Entity
#Table(name = "a")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "a_type_enum", discriminatorType =
DiscriminatorType.INTEGER)
#DiscriminatorValue("100")
public class A {
}
#Entity
#Table(name = "a")
#DiscriminatorValue("500")
public class B {
private final A a;
private String someBSpecificField;
}
If the type is a complex object then you need to annotate that type with #Embeddable and use it in your #Entity class.
if you want to override the attribute names for your #Embeddable class so they have different column names, you can do so with the #AttributeOverrides annotation.

How to override attribute from embedded column is superclass

I'm trying to override a property of an embedded column existing in the superclass of an entity.
My entities look like this:
#Embeddable
public class Key {
#Column
private String a,
#Column
private String b
}
#MappedSuperclass
public abstract class Superclass {
#EmbeddedId
private Key key;
}
#Entity
#Table(name = "my_entity")
#AttributeOverride(name = "b", column = #Column(name="renamed_b"))
public class MyEntity extends Superclass {
}
I have tried using AttributeOverride on MyEntity, but it doesn't do anything.
It would work if I would move the AttributeOverride annotation on the embedded field, but I cannot modify the superclass.
Is there any solution?
Look, read documentation carefully:
To override mappings at multiple levels of embedding, a dot (".")
notation form must be used in the name element to indicate an
attribute within an embedded attribute.
The name "b" is incorrect.
You should use "key.b"
#Entity
#Table(name = "my_entity")
#AttributeOverride(name = "key.b", column = #Column(name="renamed_b"))
public class MyEntity extends Superclass
}

JPA query results in No Identifier

I am using JPA query in spring , My subclass extends Baseclass whic contains an Id only and My subclass has all the variavles that is used by the JPA query given below:
Base Class:
#MappedSuperclass
#Table(name = "partcost")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Pg6p0012_01PartCostBaseQueryModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
String part_no;
}
Subclass :
#Entity
#Table(name = "partcost")
#NoArgsConstructor
#AllArgsConstructor
#Data
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Pg6p0012_01PartCost1QueryModel extends Pg6p0012_01PartCostBaseQueryModel implements Serializable {
private static final long serialVersionUID = 1L;
private String stock_take_cost ;
private String cost_type ;
}
when I am hiting below JPA Query :
#Repository
#Transactional
public interface Pg6p0012_01PartcostRepository extends JpaRepository<Pg6p0012_01PartCostBaseQueryModel, String> {
#Query(value = "SELECT stock_take_cost,cost_type FROM partcost where part_no = :p_part_no", nativeQuery = true)
public List<Pg6p0012_01PartCost1QueryModel>getPartcost1Result(#Param("p_part_no") String p_part_no);
}
its throwing Error: No such column name
which is clear because query is returning only one column but Model has two columns .
How to tackle this ? please suggest.
You make part_no transient . It means that it is not persisted in the database.Therefore you are getting no such column name error. Remove #Transient from the base class which is above the part_no.
And also annotate your base class with
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
Hibernate supports the three basic inheritance mapping strategies:
table per class hierarchy
table per subclass
table per concrete class

I am trying to extend a base class which has Id in two different subclass to hit JPA query [duplicate]

I am creating entities that are the same for two different tables. In order do table mappings etc. different for the two entities but only have the rest of the code in one place - an abstract superclass. The best thing would be to be able to annotate generic stuff such as column names (since the will be identical) in the super class but that does not work because JPA annotations are not inherited by child classes. Here is an example:
public abstract class MyAbstractEntity {
#Column(name="PROPERTY") //This will not be inherited and is therefore useless here
protected String property;
public String getProperty() {
return this.property;
}
//setters, hashCode, equals etc. methods
}
Which I would like to inherit and only specify the child-specific stuff, like annotations:
#Entity
#Table(name="MY_ENTITY_TABLE")
public class MyEntity extends MyAbstractEntity {
//This will not work since this field does not override the super class field, thus the setters and getters break.
#Column(name="PROPERTY")
protected String property;
}
Any ideas or will I have to create fields, getters and setters in the child classes?
Thanks,
Kris
You might want to annotate MyAbstractEntity with #MappedSuperclass class so that hibernate will import the configuration of MyAbstractEntity in the child and you won't have to override the field, just use the parent's. That annotation is the signal to hibernate that it has to examine the parent class too. Otherwise it assumes it can ignore it.
Here is an example with some explanations that may help.
#MappedSuperclass:
Is a convenience class
Is used to store shared state & behavior available to child classes
Is not persistable
Only child classes are persistable
#Inheritance specifies one of three mapping strategies:
Single-Table
Joined
Table per Class
#DiscriminatorColumn is used to define which column will be used to distinguish between child objects.
#DiscriminatorValue is used to specify a value that is used to distinguish a child object.
The following code results in the following:
You can see that the id field is in both tables, but is only specified in the AbstractEntityId #MappedSuperclass.
Also, the #DisciminatorColumn is shown as PARTY_TYPE in the Party table.
The #DiscriminatorValue is shown as Person as a record in the PARTY_TYPE column of the Party table.
Very importantly, the AbstractEntityId class does not get persisted at all.
I have not specified #Column annotations and instead are just relying on the default values.
If you added an Organisation entity that extended Party and if that was persisted next, then the Party table would have:
id = 2
PARTY_TYPE = "Organisation"
The Organisation table first entry would have:
id = 2
other attribute value associated specifically with organisations
#MappedSuperclass
#SequenceGenerator(name = "sequenceGenerator",
initialValue = 1, allocationSize = 1)
public class AbstractEntityId implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "sequenceGenerator")
protected Long id;
public AbstractEntityId() {}
public Long getId() {
return id;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "PARTY_TYPE",
discriminatorType = DiscriminatorType.STRING)
public class Party extends AbstractEntityId {
public Party() {}
}
#Entity
#DiscriminatorValue("Person")
public class Person extends Party {
private String givenName;
private String familyName;
private String preferredName;
#Temporal(TemporalType.DATE)
private Date dateOfBirth;
private String gender;
public Person() {}
// getter & setters etc.
}
Hope this helps :)
Mark the superclass as
#MappedSuperclass
and remove the property from the child class.
Annotating your base class with #MappedSuperclass should do exactly what you want.
This is old, but I recently dealt with this and would like to share my solution. You can add annotations to an overridden getter.
#MappedSuperclass
public abstract class AbstractEntity<ID extends Serializable> implements Serializable {
#Column(name = "id", nullable = false, updatable = false)
#Id
private ID id;
public ID getId() {
return id;
}
...
}
#Entity
#Table(name = "address")
public final class Address extends AbstractEntity<UUID> implements Serializable {
...
#Override
#GeneratedValue(generator = "UUID")
#GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
public final UUID getId() {
return super.getId();
}
...
}

How to mix inheritance type in JPA

How to mix single table type inheritance with join table type in the same inheritance tree?
I'm not using hibernate just JPA.
I know there is no official support for mixed inheritance by reading the JPA spec.
I can't change the architecture. It did worked with hibernate but now I need to implement this using openjpa.
I'm looking for some workaround.
this is working for me:
Superclass:
#Entity
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "TYPE_DISCRIMINATOR")
public class A extends SomeClass implements SomeInteface {
…
#Id
#Column(name = "ID", nullable = false, precision = 0)
public Integer getPk() {
return super.getPk();
}
…
Notice that "SomeClass" is not an entity.
Subclass - "JOIN" inheritance:
#Entity
#SecondaryTable(name = "A_SECOND_TABLE", pkJoinColumns = #PrimaryKeyJoinColumn(name ="ID") )
#DiscriminatorValue("BD")
public class B extends A implements SomeIntefaceB {
…
Create a new table "A_SECOND_TABLE" with join on super class Primary Key "ID".
each field that is not in join column and appears in our table is marked like this:
#Basic
#Column(table = "A_SECOND_TABLE", name = "STATUS", nullable = false, precision = 0)
Notice the table value.
Subclass – single table inheritance:
#Entity
public class C extends A implements SomeIntefaceC {...
simple single table inheritance.

Categories

Resources