Consider this simple database schema:
User Relation Property
+-------------+ +--------------+ +---------------+
| -user_id | | -relation_id | | -property_id |
| | | -source_id | | |
| | | -target_id | | |
| | | -type | | |
+-------------+ +--------------+ +---------------+
The relation table contains multiple source and target ids (as STRING) from another tables and "connect" dynamically difficult types of entities. So the source_id can be a user_id and target_id property_id, but also other entities and vice versa.
Now I want in User the properties over the relation table when type is property.
#OneToMany(mappedBy = "source", fetch = FetchType.EAGER)
#Where(clause = "type = 'PROPERTY'")
#ElementCollection
private Set<Relation> properties;
This works perfectly fine. I receive the relation entity with the property id as string in target_id.
Is it possible to resolve this and extend the getter, so that i receive the real property entity?
Like calling the propertyRepository within the user entity. As a newbie in java and jpa/hibernate im a bit lost here.
Related
I'm working with a non normalized 3rd party database meaning I cannot change the schema. I'm trying to map the tables to JPA entities using Hibernate 5.1
There are 2 simple tables A and B:
| A_ID(pk) | | B_ID(pk) |
------------- -------------
| 1 | | 1 |
------------- | 2 |
-------------
Table C has a composite primary key and has a Many-To-One relation to Table A:
| A_ID(pk&fk) | QUANTITY(pk) | VALID_FROM(pk) |
---------------------------------------------------
| 1 | 1 | 2017-05-21 |
| 1 | 1 | 2018-01-01 |
| 1 | 2 | 2017-05-21 |
Table D has a composite primary key:
| A_ID(pk&fk) | QUANTITY(pk) | VALID_FROM(pk) | B_ID(pk&fk) |
--------------------------------------------------------------------
| 1 | 1 | 2018-01-21 | 1 |
| 1 | 2 | 2018-01-21 | 1 |
| 1 | 2 | 2018-05-01 | 2 |
the VALID_FROM column is not part of the join condition between the tables and can take up any value.
I'm trying to set up a relation between Table C and D but because of the VALID_FORM primary key component they cannot be modelled with Many-To-One. And since there is no join table they cannot be modelled with Many-To-Many either.
The best solution would be to create a view like
CREATE VIEW C_NORM AS
SELECT DISTINCT A_ID, QUANTITY
FROM TABLE_C;
which would produce view C_NORM:
| A_ID(pk&fk) | QUANTITY(pk) |
----------------------------------
| 1 | 1 |
| 1 | 2 |
Creating the C_NORM entity on this view could have
a One-To-Many relation with Table C
and another One-To-Many relation with Table D
but I cannot change the schema thus I cannot create a new view.
Is there any way to define an entity as a class with annotations that is basically based on a native SQL query rather than a view or table in the DB?
No that's not possible and it doesn't make sense.
Entities are for update, insert and delete. If you don't want to do any of these operations you shouldn't use entities.
You can use the #SqlResultSetMapping to map a result of a native query to a class
Query q = em.createNativeQuery(
"SELECT c.id, c.name, COUNT(o) as orderCount, AVG(o.price) AS avgOrder " +
"FROM Customer c " +
"JOIN Orders o ON o.cid = c.id " +
"GROUP BY c.id, c.name",
"CustomerDetailsResult");
#SqlResultSetMapping(name="CustomerDetailsResult",
classes={
#ConstructorResult(targetClass=com.acme.CustomerDetails.class,
columns={
#ColumnResult(name="id"),
#ColumnResult(name="name"),
#ColumnResult(name="orderCount"),
#ColumnResult(name="avgOrder", type=Double.class)})
})
Or alternatively use QLRM: https://github.com/simasch/qlrm
I am having issues mapping the following using spring JPA. Let's say I have a order table which has two primary keys. one is a foreign key to customer and another is a foreign key to order Type as seen below:
Customer
+----+------+--+
| id*| name | |
+----+------+--+
| 1 | Joe | |
+----+------+--+
Order
+------------+-------------+
| customerId | orderTypeId |
+------------+-------------+
| 1 | 1 |
+------------+-------------+
OrderType
+----+--------+
| id | type |
+----+--------+
| 1 | online |
+----+--------+
the idea is each customer has a one to many relationship with Orders. the primary key of orders is a combination of the two foreign keys.
any help would be appreciated.
I have two SQLContainers with the folowing data structure:
SQLContainer SP:
FullUserName | tel | room
SQLContainer MT:
FullUserName | ComputerName | Domain | OS
In my opinion, the foreign key of the both SQLContainers could be: "FullUserName" field?!
How can i set relation (reference) between these containers to get the finally view like this:
FullUserName | tel | room | ComputerName | Domain | OS
?
I have a xlsx file, that has some tabs with different data. I want to be able to save each row of a tab in a list. The first thing that comes to mind is a list of lists, but I was wondering if there is another way. I'd like to save that information in a object, with all its benefits, but can't think of a way to generate/create such diverse objects on the fly. The data in the xlsx is diverse and ideally the program is agnostic of any content.
So instead of e.g. create a list for each row, than put that list in another list for each tab and each tab in another list, I'd like to store the information that each row represents in a single object and just have a list of different objects.
A small graphic to visualize the problem :
+--------------------------------------------------------------------+
|LIST |
| |
| +------------------+ +------------------+ +-----------------+ |
| | Class1 | | Class2 | | Class3 | |
| |------------------| |------------------| |-----------------| |
| | var1 | | var1 | | var5 | |
| | var2 | | var2 | | var6 | |
|... | var3 | | | | var7 |...|
| | | | | | | |
| | | | | | | |
| | | | | | | |
| | | | | | | |
| +------------------+ +------------------+ +-----------------+ |
| |
+--------------------------------------------------------------------+
How about a generic class Row which will contain all the information in a row from your file. Then you simply create a list of Rows. Methods for the Row can allow you to get each column.
Without knowing more about the data, you will not be able to write classes to encapsulate it. You could "dynamically" create classes to create new source code. But then the question is, how would you use the new classes?
Well since you want to avoid a "list of lists" kind of solution there would be another way.
This might not be very efficient or fast but I don't have any experience with it, so maybe it isn't too bad. Here's the idea:
For each Row:
Use javassist to create as many fields as needed dynamically that contain each cell's information. Then create an instance of this class and store it in your list of rows. You could also add a field with information about this particular row (e.g. how many fields there are or their names or types or whatever you might need).
The number of fields or methods could also be determined using Reflection.
To get started with javassist there's a tutorial here.
Besides that I don't think there's much to do that does not involve some sort of List<List<SomeType>>
I'm trying to convert part of a data-access layer into hibernate and running into some trouble getting the collection association right. I am using hibernate annotations, and have two Entities that are related (the base configuration here is working, just not the join). Some names have been obfuscated:
Spring 3, Hibernate 3, Java 6, MySQL 5.
Container has a List of Videos. Both of these classes are mapped in hibernate with annotations.
Unfortunately, the mapping table has an unusual schema. It looks like this:
container_mapping:
+-----------------+------------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+-------------------+-------+
| internal_id | int(10) unsigned | NO | PRI | | |
| external_id | varchar(255) | NO | PRI | | |
| mapping_type_id | int(4) unsigned | NO | PRI | | |
| creation_date | timestamp | NO | | CURRENT_TIMESTAMP | |
+-----------------+------------------+------+-----+-------------------+-------+
internal_id maps to container.id and external_id maps to video.id when mapping_type_id = 2
The query to pull back by id:
select * from container c, container_mapping cm, video v where cm.mapping_type_id=2 and c.episode_id = cm.internal_id and cm.external_id = v.id and c.episode_id=?;
I can't seem to find a good example to having a collection join WITH a join field having a specific value. At this point I'm grasping at straws. The (incomplete) version is here:
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#JoinTable(name="container_mapping",
joinColumns = #JoinColumn(name="external_id"))
private List<Video> videos = Lists.newArrayList();
Anyone have any pointers on how to proceed?
You could try mapping the videos collection this way:
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#JoinTable(name="container_mapping",
joinColumns = #JoinColumn(name="internal_id"),
inverseJoinColumns = #JoinColumn(name="external_id")
#WhereJoinTable(clause="mapping_type_id=2")
private List<Video> videos = Lists.newArrayList();
The idea behind this mapping is following:
The joinColumns parameter of the #JoinTable annotation is used to configure the column, which stores the value of container id.
The column storing the video id is configured by using the inverseJoinColumns parameter of the #JoinTable annotation.
The #WhereJoinTable annotation can be used to restrict the rows selected from the join table. The clause parameter must be written by using SQL. In this case it used to restrict the value of mapping_type_id, which must be 2.