Scenario:Let us assume a unidirectional relationship A->ManyToOne->B ( hence 2 tables A and B) in JPA. Typically, this will be mapped in Entity A as:
#ManyToOne
#JoinColumn
B b;
Table A will hence contain a foreign key which will be primary key in Table B.
Further, let us assume that B is a table that contains static values.
In JPA the * -> One mappings are eager by default. To avoid an extra query, I can always do a join fetch to avoid the extra query.
I understand how enums can be used/converted to store a column value in a table.
Questions:
Would it really be a value addition to have an enum representation
for the static values when we already have a table and hence an
entity for table B?
If we do have an enum,is it possible to convert the entity B to an
enum (representing static values) and vice versa? I have usually
seen enum converted into a column in table and not a complete
entity/row in a table.
Even if the above works and we want to retrieve A and B, can the
enum be used to avoid the extra join (without the fetch join) while
doing the conversion?
Related
Using Spring Boot and Spring Data JPA, I have a table which represents an enum value, and a corresponding entity that I want that one of its field will be 'all the possible values the enum can have', i.e. a field possibleValues that will be a select all on the other table. Preferably I don't want to have a relationship like #ManyToMany since:
It will always be a select all, I don't want to save to the database all the options and update them each time the enum values table changes.
I am going to have several enums, so for each enum create another many-to-many is less than ideal.
I've tried to find something like #Formula that will let me select all the values from another table, but it doesn't seem to work:
#Transient
#Formula("select e.name from EnumTable e")
private List<String> possibleValues;
results in possibleValues always being null, and if I remove the #Transient I have to define the relationship between the two entities.
For Enum value in database, I recommend using string (for object, you can use JSON to convert first before store and covert back after retrieve )
I am using currently Spring Data JPA and I would like to map an attribute
#Entity
public class Outer {
...
Map<String, List<String>> typesToCategories;
}
Let's assume I have a tables outer and outer_type_category. The first one is trivial: only column outer_id is relevant from it
CREATE TABLE outer_types_categories (
id uuid NOT NULL,
outer_id uuid NOT NULL,
type character varying(128) NOT NULL,
category character varying(128) NOT NULL,
...
)
Which annotations should I use (if it is possible in general) to map this table to the map?
I have tried to use this
#ElementCollection
#CollectionTable(name = "outer_type_category", joinColumns = [JoinColumn(name = "outer_id")])
#MapKeyColumn(name = "type")
#Column(name = "category")
Map<String, List<String>> typesToCategories;
but in the end I see an exception:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.List, at table: outer_type_category, for columns: [org.hibernate.mapping.Column(category)]
Did I forget anything?
JPA specifies that
A persistent field or property of an entity or embeddable class may
correspond to a collection of a basic type or embeddable class
(“element collection”).
(JPA 2.2 Specification, section 2.6; emphasis added)
java.util.List is neither a basic type nor an embeddable class, so it is not among the allowed element types of an element collection. Moreover, JPA goes on to say
An embeddable class [...] that is contained within an element
collection must not contain an element collection
, so even replacing List with an embeddable class does not give you a suitable mechanism for mapping the structure you've described. If you're unwilling or unable to change the DB structure at all, then I don't think you can map your table in a manner that is in any way analogous to what you describe.
If you can at least add a new table to the DB then you can introduce a new entity representing an entry in your map, say OuterType, which has an element collection mapped to your outer_types_categories table. It would probably need to have a composite ID corresponding to (outer_id, type). Even then, the DB side would need to be set up to automatically assign values to the id column of the collection table (unless you can drop that column, which in truth does not appear to be useful for your apparent purposes), because members of an element collection are not entities, and therefore JPA does not ascribe IDs to them. Moreover, it is messy (on the JPA side) to have a column that is both part of a composite primary key and a foreign key for a related entity, as this would require.
If you have more freedom to modify the DB structure then I'd set up the aforementioned OuterType entity with a standard, surrogate ID and a bidirectional one-to-one relationship with Outer, represented on the Outer side as a map. Set up an element collection containing the category strings in OuterType using the default mapping strategy, which would use OuterType's (surrogate) ID and neither its "type" nor its "outer_id" in the collection table.
I have following tables:
master_table(id, col1, col2, discriminator_col)
join_table1(m_id, v_id)
value_table1(id, val)
join_table2(m_id, v_id)
value_table2(id, val)
there is single master table and several value tables joined to master table via join tables. Value tables contain single scalar value for each master_table row. Values from separate values tables are placed into descendant entities, so there are one MasterEntity and several Child1Entity, Child2Entity etc.
I would like not to create a separate entity for each value_table, just for each ChildEntity and somehow join value table to that entity.
MasterEntity:
#Entity
#Inheritance(...) // not sure what type of inheritance to use
public class MasterEntity {
#Id
private int id;
private String col1;
private String col2;
}
Child1Entity:
#Entity
public class Child1Entity extends MasterEntity {
// need to get value_table1.val column here
}
I could create entity for value_table and add many-to-one relation to Child1Entity, but if it is possible to avoid I would like to do that.
I tried to add two secondary tables (join_table1, value_table1) to Child1Entity, but I can not join join_table1 with value_table1, just with master_table.
If you want to use #Inheritance, you can't have those join_tables. With those join tables, your model says:
one value can belong to multiple master rows
one master row can belong to multiple value rows
If you just want: 1 master belongs to 1 value row, than use this:
master (id, ...)
value1 (masterId, ...)
value2 (masterId, ...)
With #Inheritance(strategy=InheritanceType.JOINED).
For more information have a look here: http://en.wikibooks.org/wiki/Java_Persistence/Inheritance
BUT: Whenever you use #Inheritance you will have to create a separate #Entity class for everything.
If you really need the 5 table layout from above, use #ManyToMany.
Basically JPA is made for Mapping Java Objects to SQL Tables, not the other way round ;) If you need to do thing's which aren't possible using JPA (or too complicated), you can always use JDBC and craft your queries and Entity mappings by hand.
I have entities A and B, and A can have set of B. The same instance of B can belong to several A. So there is classical many-to-many relation here.
In GAE there is no direct support of many-to-many relations, instead they're offering an ability to use sets of keys for related relations. So in A I will maintain set of keys of records in B.
Now the problem is - how can I query for objects of type B belonging to given object of type A and matching certain criteria? In plain SQL I would do that like:
select B.*
from
B inner join A
on B.A_ID=A.ID
where B.property0=criteria1
and B.property1=criteria2 ...
and ...
but because I can not do JOIN then I need to do something like
select B.*
from B
where B.A_ID in ( ... )
and B.property0=criteria1
and B.property1=criteria2 ...
and ...
so the query itself can be very long because of amount of IDs.
Is there any better way?
If you refactor your relationship mapping you can get a better query. Instead of storing a set of keys in A, store a set of keys in B. Then you can query with
select * from B where a_id = {idOfRelevantA} and property0 = {criterion0} and property1 = {criterion1}...
This way you avoid the multiple queries that the in operator creates.
Also, beware: in will only work for a list of 30 elements or fewer.
I have a table with 11 columns, but I need to get only 2 of them in my application, I'm using spring/hibernate/DAO combination. For now I have a domain class which includes all 11 fields, and mapping file which maps all 11 columns in table. How do I use get just 2 of them not all?
Either:
Use projections - Pro: nothing to add - Con: Not typesafe (the result is a List of rows where each row is anObject[]):
select f.foo, f.bar from FatEntity f
Use a constructor expression in the SELECT clause (the specified class is not required to be an entity or to be mapped to the database) - Pro: typesafe solution - Con: More classes, unless you reuse FatEntity as holder in which case many fields will be null:
select new com.acme.FatEntityDetails(f.id, f.foo, f.bar) from FatEntity f
Note that if an entity class name is specified in the SELECT NEW clause, the resulting entity instances are in the new state (no persistent identity).
Use another entity mapped on the same table with only the required fields - Pro: It's a real entity that you can modify and update - Con: More classes.
from LightEntity
The main differences between #2 and #3 are:
2 doesn't require the holder to be an entity at all.
the holder in #2 could be an entity mapped on another table.
if #2 returns entities, they are in a new state (this might be a problem, or not).
Try:
SELECT myEntity.one, myEntity.two FROM MyEntity myEntity
You can even do :
SELECT new MyEntityDescription(myEntity.one, myEntity.two) FROM MyEntity myEntity
to get a list of entity descriptions.
If you never need more than those 2 columns of the table, you could change your hibernate mapping to map only those 2 needed columns to the entity class. Only map those table columns you want to access in your application. Keep in mind, that database constraints on the "ignored" columns can be violated like not null constraints, foreign keys or unique constraints.