I'm doing a left join of Table A and Table B and trying to fetch the results into a custom POJO which has fields from both Table A and Table B as follows:
List<MyCustomPojo> res = create.select()
.from(TABLE_A)
.leftJoin(TABLE_B)
.on(TABLE_A.MY_CODE.eq(TABLE_B.MY_CODE))
.fetchInto(MyCustomPojo.class);
It works fine for all the fields except for the field myCode the one on which these two tables are joined. For me the values for myCode were picked up from the right table, Table B, which is NULL for all of those records in Table A that do not have a corresponding entry in Table B. I would like to know how jooQ decides which field to map to POJO and if this behavior is documented anywhere.
My goal is to fetch all the fields from Table A and Table B into the custom POJO such that myCode is picked up from the left table. I would appreciate your advice on the right way to achieve it.
The default behaviour of ResultQuery.fetchInto(Class) (and most other into(Class) methods) is specified in DefaultRecordMapper. It can be overridden globally by providing a custom RecordMapperProvider in your Configuration.
In your particular case, DefaultRecordMapper will map all values from your records in field order. If there's a column that appears twice, it will be mapped twice, meaning that the second value will persist in your resulting object. There are two easy workarounds:
Don't select the "wrong" myCode. This is really the most robust solution
List<MyCustomPojo> res = create
.select(TABLE_A.fields())
.select(/* all fields in TABLE_B except the ones you don't want */)
.from(TABLE_A)
.leftJoin(TABLE_B)
.on(TABLE_A.MY_CODE.eq(TABLE_B.MY_CODE))
.fetchInto(MyCustomPojo.class);
Use RIGHT JOIN instead:
Perhaps a bit of a hack, but this will quickly reverse the table order in your SELECT statement.
List<MyCustomPojo> res = create
.select()
.from(TABLE_B)
.rightJoin(TABLE_A)
.on(TABLE_A.MY_CODE.eq(TABLE_B.MY_CODE))
.fetchInto(MyCustomPojo.class);
Finally a use-case for RIGHT JOIN :)
Note, this is the only solution that will also prevent wrong values for other columns that "accidentally" share the same name.
Add the "correct" myCode field once more.
Another hack, but it will work around the issue you're experiencing:
List<MyCustomPojo> res = create
.select(TABLE_A.fields())
.select(TABLE_B.fields())
.select(TABLE_A.MY_CODE)
.from(TABLE_A)
.leftJoin(TABLE_B)
.on(TABLE_A.MY_CODE.eq(TABLE_B.MY_CODE))
.fetchInto(MyCustomPojo.class);
Related
In the database of my app there are currently 3 tables:
Parent Table - (general goal)
ChildA
ChildB
If I were to speak in terms of OOP, both ChildA and ChildB are "subclasses" of the Parent table, however they are not similar.
The Relationships between the tables:
A row in the Parent Table has an integer that defines whether the row is related to type A (ChildA) or type B (ChildB).
In both ChildA and ChildB there is a reference to the related row in Parent Table (id). There can be only 1 Parent row related to a child and there can also be 1 child related to a parent (one-to-one r/s).
There is not any pair of columns with the same name inside all of the tables.
What I'm trying to do is to basically retrieve all of the rows in the Parent table, then according to the type column of each row to retrieve additional related info from either ChildA or ChildB.
This would be very easy to do if I were to first retrieve all of the parent rows, and then run through the rows with a loop and query n times for every row, but that would probably be highly inefficient, I guess.
I was wondering whether there is a better approach to this, perhaps even in a single query.
I know I could use INNER JOIN or something, but I'm not sure how it'd work in this case where I need to join 2 tables with a third one (and where the columns are different both in number and content).
So the question is, what would be the most efficient way to preform it?
EDIT:
I saw this question was marked as a duplicate of another question, however, I do not ask how to design my database, but how to QUERY it.
I'm using a Table-Per-Type design, and would like to get all of the rows from all of the different types (currently 2).
I would know how to do so in a case where I wanted to get all of the rows from a single type, but not in this situation, which is why I'm asking whether and how it would be possible with a single query (with a mechanism similar to JOIN for example). I know I could achieve it by querying twice, but I'd like to learn a more efficient way to do it.
I can think of two different approaches (with their pluses and minuses :)
1) Have as many queries as subtypes and retrieve a subtype at a time. In the example case, you will have two queries:
select * from ChildA where id in (select childId from Parent where childType='A')
select * from ChildB where id in (select childId from Parent where childType='B')
This will give you the lowest possible data transfer between your application and the database at a relatively reasonable performance. You will "waste" the effort your database makes to filter the Parent table (the database will have to do it twice)
2) You have one query which retrieves both ChildA and ChildB as part of the same result set like this:
select ChildA.*, ChildB.* from Parent
left outer join ChildA on Parent.ChildId=ChildA.id
left outer join ChildB on Parent.ChildId=ChildB.id
The above query only works if children have unique ids (that is, if there is a ChildA with id 5, there is no ChildB with id 5). If this is not the case, you need a slightly "uglier" query:
select ChildA.*, ChildB.* from Parent, ChildA, ChildB
where (Parent.ChildType='A' and Parent.ChildId=ChildA.id) or
(Parent.ChildType='B' and Parent.ChildId=ChildB.id)
This will give you a result set which contains all columns from both ChildA and ChildB with many NULL values (for each ChildA record, all ChildB columns would be NULL). This way, you have a single query (which may perform faster that the multiple queries in the first approach), but you need to ship more data.
You can create a join for this like this:
select * from (a outer join b on a.key = b.fg_key) outer join c on a.key = c.fg_key
I am not 100% sure about the placement of the opening brace but I remember using this before
But as the amount of sub-types grows, it will become more and more complex to maintain this properly, all column names must be aliased in the query. It would be easiest to perform a two step load, first load all items of type 1, then of type 2. This will keep the code cleaner and easier to maintain.
Efficiency-wise I don't expect this to be much slower than a single query. I would suggest going with the multiple query variant in the first version and optimize when performance becomes an issue.
Basically this kind of requirement we should try to handle in our programme
we should not try to achieve from database.
However I tried below query where we it outputs from one of the child table and in other child only null;
select parent.id, parent.description, (select name from car where id = parent.id) as child1, (select Name from bike where id = parent.id) as child2 from vehicle parent;
Hope this will help you.
I am attempting to create a domain/entity class based on a complex query. The query unions a bunch of tables together and unfortunately I am not able to create a view on the database for this query. I have been trying to set up the entity object but I am unsure of how to ensure that the marshaling works properly (and ensure the entity acts as read-only object).
As an example of the query, I am doing something like this:
Select
U_T.a,
U_T.b,
U_T.c,
C_T.a
FROM
(select
A_T.a,
null as b,
A_T.c,
1 as ind
from A_T
UNION
select
B_T.a,
B_T.b,
null,
0 as ind
FROM B_T
) U_T
left outer join C_T on C_T.fk_a = U_T.a;
The other issues are that this union can result in instances where there is no unique key column. This is fine as this data is for viewing only, and never editing. However the #Entity annotation wants a column to be listed with the #ID annotation. Another issue is that I do not believe I can use the other entity classes as the goal is to reduce the number of DB transactions from this query (as the actual one can result in hundreds of recursive queries being performed).
If I need to give any more information please let me know.
I have many tables in my DB with exactly the same structure: same columns names and types.
The only difference between these tables is the their names (which I can only know in runtime).
I would like to create a mapping of a class to a table but giving the name of the table only during runtime (no static #Table annotation).
Is it possible?
Is there any other way to achieve my goal?
Directly - no. Because this is not a regular use-case. Normally you should not have dynamcally-generated tables. It is a valid use when you move some records to an archive table (or tables), but otherwise avoid it.
Anyway, you can make that work: make a native query, and map the result to your non-entity object. You will be able to select from any table and transform the result to an object. However, you can't insert or update that way.
Don't think associating or changing the table mapped to an entity dynamically is possible.
You can check #MappedSuperClass, which will allow you to define all fields in a class once and inherit them, so that there is no repetition and entities are empty class with mappings.
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html_single/#d0e1168
If you know the table name dynamically you can always instantiate the mapped class accordingly.
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.
I'm mapping a proprietary database to Hibernate for use with Spring. In it, there are a couple of jointables that, for entity A and entity B have the following schema:
CREATE TABLE AjoinB (
idA int not null,
idB int not null,
groupEnum enum ('groupC', 'groupD', 'groupE'),
primary key(idA, idB, groupEnum)
);
As you can see, this indicates that there can be multiple A-B relationships that put them in different groups. I'd like to end up with, first line for entity A and second for entity B, the following sets
Set<B> BforGroupC, BforGroupD, BforGroupE;
Set<A> AforGroupC, AforGroupD, AforGroupE;
So far, I've only managed to put them in one set and disregard the groupEnum relationship attribute:
#ManyToMany(targetEntity=B.class, cascade={ CascadeType.PERSIST, CascadeType.MERGE } )
#JoinTable(name="AjoinB", joinColumns=#JoinColumn(name="idA"), inverseJoinColumns=#JoinColumn(name="idB") )
private Set<B> BforAllGroups;
and
#ManyToMany( mappedBy = "BforAllGroups", targetEntity = A.class )
private Set<A> AforAllGroups;
How can I make multiple sets where they belong either in groupC, groupD or groupE?
Cheers
Nik
If you're considering doing this, don't. Tables are cheap nowadays what's with the economy and all, so just create one per association; it'll be so much easier.
If you're bound by a legacy database and you can't change the structure of that table I would
Consider skaffman's solution first (+1, btw). Depending on your target database you may be able to write a trigger for your views that would insert adequate "discriminator" value.
If the above isn't possible in your DB, another solution is to use custom SQL for CRUD operations for your collections. Keep in mind that this will NOT work (e.g. your "discriminator value" won't get applied) for complex HQL queries involving your association as part of condition. You can also mix / match this with above - e.g. use views and use custom SQL for insert / delete.
If both of the above fail, go with "association as a separate entity" as suggested by framer8. That's going to be rather ugly (since we're assuming here you can't change your tables) due to composite keys and all extraneous code. It may, in fact, be impossible if any of your associations allows duplicates.
To my knowledge, Hibernate cannot use such a "discriminator" column in the way that you want. Hibernate requires a join table for each of them.
Perhaps you might be able to define additional views on the table, showing each of the groupings?
I think the advise anytime you need to access a field in a link table is to make the link table an object and a hibernate entity in its own right. A would have a set of AtoB objects and AtoB would have a set of B objects. I have a simmilar situation where the link table has a user associated with the link.
select joinTable.b from A a
left join a.AtoB joinTable
where joinTable.group = 'C'
It's not as elegant as having an implicit join done by hibernate, but it does give you the control you need.