Reputation: 347
This is similar to JPA mapping views and tables with inheritance but since accepted answer does not satisfy me I decided to ask my own question.
I have one based class that holds common fields for all entities
@MappedSuperclass
@Access(AccessType.FIELD)
public abstract class CommonFields{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
(...)
}
Lets say I have one entity called Table
@Entity
@Table(name = "my_table")
public class Table extends CommonFields{
(..)
}
This works perfectly for me. I created view, which adds one column to my_table
. I mapped it this way:
@Immutable
@Entity
@Table(name = "my_table_plus_view")
public class TableView extends Table{
(..)
}
TableView
is read_only. This is simple Table
with additional informations for presentation purposes.
This application runs on Tomcat and Postgres DB. Server starts whithout errors but when I try to get all records from view I got an error that my Table
does not contain DTYPE
column. I know what it is and how it works but since I don't need it I don't want it.
I want read/write my Table
just like now but I don't know how to map my TableView
so JPA query can use it. I did some efforts whith InheritanceType
but with no success. If I copy all fields from Table
to TableView
then my application will run just as expected but this this doesn't suit me. How can I map my view so I can use inheritance?
Upvotes: 2
Views: 5219
Reputation: 23226
You could have one Entity mapped to 2 tables (or a table and a view in your case). You can use @SecondaryTable
. The columns of the view then become properties of the entity Table and can be queried like any other.
To ensure immutability you can mark the column you can use the insertable
and updatable
properties of @Column
.
@Entity
@Table(name = "my_table")
@SecondaryTable(name = "my_table_plus_view")
public class Table extends CommonFields{
@Column(name="col_from_view", table="my_table_plus_view",
insertable=false, updatable = false)
private String someField;
}
https://en.wikibooks.org/wiki/Java_Persistence/Tables#Multiple_tables
In this scenario your application is then dealing only with one entity.
An alternative would be to create a new Entity pointing to the view and map it from Table using a @OneToOne
. As long as this relationship always exists (i.e. is marked as optional=false
) then this approach has the benefit of only loading the view data on demand whereas with the @SecondaryTable
option the join will be performed on each load. Clients of your model could still deal only with one entity as you do not need to expose the second entity to the outside world:
@Entity
@Table(name = "my_table")
public class Table extends CommonFields{
//can be lazily loaded only when optional = false
//see: http://stackoverflow.com/questions/17987638/hibernate-one-to-one-lazy-loading-optional-false
@OneToOne(optional = false)
@JoinColumn(name = "x")
private TableView tableView;
public int getCalculatedValue(){
return tableView.getCalculatedValue();
}
}
@Entity
@Table(name = "my_table_plus_view")
public class TableView{
private int calculatedValue;
}
In an alternative scenario you can use inheritance as you have tried above. Your application would then expose 2 entities Table and TableView. As you have 2 separate tables you would need to indicate that you wanted to use a Joined inheritance strategy. This is the bit that is missing in your code:
https://en.wikibooks.org/wiki/Java_Persistence/Inheritance#Joined.2C_Multiple_Table_Inheritance
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@Table(name = "my_table")
public class Table extends CommonFields{
}
@Entity
@Table(name = "my_table_plus_view")
public class TableView extends Table{
}
With the Joined strategy Hibernate does not require a discriminator column.
Upvotes: 6