class Contact{
int uniqueId;
String name;
Account account;
}class Account{
int id;
String name;
}public List<Contact> getContactListByUniqueID(List<String> uniqueids) {
Map<String, List<String>> namedParameters = Collections.singletonMap("ids", uniqueids);
return SQLUtils.namedListQuery(namedParameterJdbcTemplate,"Select* from contact left join account on contact.accountid = account.id where UniqueID in (:ids)",namedParameters,RowMapperFactory.getContactRowMapper());
}public static RowMapper<Contact> getContactRowMapper(){
return new RowMapper<Contact>() {
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException, DataAccessException {
Contact c = new Contact();
c.setFirstname(rs.getString(Contact.Firstname));
//fill all
c.setAccount(RowMapperFactory.getAccountRowMapper().mapRow(rs,rowNum)); //AccountMapper same style as ContactMapper
return c;
}
}select * from contact where uniqueid in (:ids);
select * from account where id in (select accountid from contact where uniqueid in (:ids));create.selectFrom(BOOK).orderBy(BOOK.ID).fetch().map(new RecordMapper<BookRecord, Integer>() {
@Override public Integer map(BookRecord book) {
return book.getId();
}
};public static RecordMapper<ContactRecord, Contact> getContactRowMapper(){ return new RecordMapper<ContactRecord, Contact>() { @Override public Contact map(ContactRecord record) { Contact c = new Contact(); c.setFirstname(record.getValue(table.Firstname)); //whereever i would get the table from return c; } } } }--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
public class MyRecordMapperProvider implements RecordMapperProvider {
@Override public <R extends Record, E> RecordMapper<R, E> provide(RecordType<R> recordType, Class<? extends E> type) { if (type == Account.class) { return (RecordMapper<R, E>) getAccountRecordMapper(); } return new DefaultRecordMapper(recordType, type); }
public static RecordMapper<TAccountRecord, Account> getAccountRecordMapper() { return new RecordMapper<TAccountRecord, Account>() { @Override public Account map(TAccountRecord record) { Account c = new Account(); c.setId(record.getId()); c.setName(record.getName()); c.setCreateTime(record.getCreatetime()); return c; } }; }
}
@Test
public void myTest(){
TAccount a = new TAccount(); List<Account> accountList = create.select(a.fields()).from(a).fetch().map(CockpitRecordMapperProvider.getAccountRecordMapper());}
The method map(RecordMapper<? super Record,E>) in the type Result<Record> is not applicable for the arguments (RecordMapper<TAccountRecord,Account>)
<!-- jooq --> <!-- Configure jOOQ's ConnectionProvider to use Spring's TransactionAwareDataSourceProxy, which can dynamically discover the transaction context --> <bean id="transactionAwareDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> <constructor-arg ref="dataSource_mysql" /> </bean>
<bean class="org.jooq.impl.DataSourceConnectionProvider" name="connectionProvider"> <constructor-arg ref="transactionAwareDataSource" /> </bean> <bean id="exceptionTranslator" class="com.westhouse.jooq.exception.ExceptionTranslator" /> <!-- Invoking an internal, package-private constructor for the example Implement your own Configuration for more reliable behaviour --> <bean class="org.jooq.impl.DefaultConfiguration" name="config"> <constructor-arg index="0" ref="connectionProvider" /> <constructor-arg index="1"><null /></constructor-arg> <constructor-arg index="2"><null /></constructor-arg> <constructor-arg index="3"> <list> <bean class="org.jooq.impl.DefaultExecuteListenerProvider"> <constructor-arg index="0" ref="exceptionTranslator"/> </bean> </list> </constructor-arg> <constructor-arg index="4"><null /></constructor-arg> <constructor-arg index="5"><value type="org.jooq.SQLDialect">MARIADB</value></constructor-arg> <constructor-arg index="6"><null /></constructor-arg> <constructor-arg index="7"><null /></constructor-arg> </bean> <!-- Configure the DSL object, optionally overriding jOOQ Exceptions with Spring Exceptions --> <bean id="dsl" class="org.jooq.impl.DefaultDSLContext"> <constructor-arg ref="config" /> </bean> <!-- joo end -->
DSL.using(new DefaultConfiguration()
.set(connection)
.set(SQLDialect.ORACLE)
if (type == Account.class) { return (RecordMapper<R, E>) getAccountRecordMapper();}return new DefaultRecordMapper(recordType, type);The provider goes into the right direction of centralizing my mappers, but its not yet the best solution. Is there an abstract class of the RecordMapperProvider interface also available? I´m asking as i like it more to specify the parameter class
directly to get a specific AccountRecordMapperProvider instead of a generic method where i have to conditionally ask for each class type and eventually return the defaultrecordmapper instead of throwing an exception,
when the appriopriate class mapper cannot be found, which IMO leads to bad behaviour.if (type == Account.class) {return (RecordMapper<R, E>) getAccountRecordMapper();}return new DefaultRecordMapper(recordType, type);
I dont think the default mapper could not map anything right in my cases, the fallback therefor is for me more pain than gain.maybe this thoughts are a leftover excessive spring row mapper using, but it just somehow feels bad.
On a sidenote: You probably shouldn't assume in your account record mapper that you will be getting a TAccountRecord. In your particular query, that might be the case but as soon as you join tables or reduce the number of fields, you might get something else...In particular, when you use select(Field[]).from(some table), then there is no way that jOOQ can still know the record type that you have in mind (TAccountRecord). In fact, it could be any record type, you're passing a Field[] argument to the SELECT clause, which is why you will get the much more general Record type from your fetch() method - with no type information.
public <R extends Record, E> RecordMapper<R, E> provide(RecordType<R> recordType, Class<? extends E> type) {
// UUID mappers will always try to find the ID column if (type == UUID.class) { return new RecordMapper<R, E>() { @Override public E map(R record) { return (E) record.getValue("ID"); } } } // Books might be joined with their authors, create a 1:1 mapping if (type == Book.class) { return new BookMapper(); }
// Fall back to jOOQ's DefaultRecordMapper, which maps records onto // POJOs using reflection. return new DefaultRecordMapper(recordType, type);}TAccount a = new TAccount();List<Account> accountList = create.select(a.fields()).from(a).fetch().into(Account.class);On a sidenote: You probably shouldn't assume in your account record mapper that you will be getting a TAccountRecord. In your particular query, that might be the case but as soon as you join tables or reduce the number of fields, you might get something else...In particular, when you use select(Field[]).from(some table), then there is no way that jOOQ can still know the record type that you have in mind (TAccountRecord). In fact, it could be any record type, you're passing a Field[] argument to the SELECT clause, which is why you will get the much more general Record type from your fetch() method - with no type information.OK got it!In the RecordMapper i could subselect other predefinded Record mappers, but where do i get the table instances from? As in your examples you always directly use String column References to identify the field columns:
public <R extends Record, E> RecordMapper<R, E> provide(RecordType<R> recordType, Class<? extends E> type) {// UUID mappers will always try to find the ID columnif (type == UUID.class) {return new RecordMapper<R, E>() {@Overridepublic E map(R record) {return (E) record.getValue("ID");}}}// Books might be joined with their authors, create a 1:1 mappingif (type == Book.class) {return new BookMapper();}// Fall back to jOOQ's DefaultRecordMapper, which maps records onto// POJOs using reflection.return new DefaultRecordMapper(recordType, type);}but isnt that the opposite of jooqs targets?
How do i get the referenced tables from the origin select:
alias, right?TAccount a = new TAccount();List<Account> accountList = create.select(a.fields()).from(a).fetch().into(Account.class);
like TAccount a, where i maybe also defined an alias, inside the RecordMapper? If i would create an new instance of TAccount inside the RecordMapper i could address the field columns statically but i would loose the
so how do i get the references for all joined tables from inside the RecordMapper where i only have access to the class type and the generic Record?
Or is the RecordMapper approach not designed for may particular use case as described? If so, the record mapper is probably only useful directly inline or for specific purpose, is that correct?
Best regards and happy holidays
But I'm afraid that it might be trying to re-normalise flattened result sets, that have been denormalised by random joins. In that case, I don't think there will be a reliable solution.
TAccount a = new TAccount("a,");TContact c = new TContact("c");List<AccountContact> list = create.select(a.NAME,c.FIRSTNAME, c.LASTNAME).from(a.leftOuterJoin(c).on(a.ID.eq(c.ACCOUNTID))).fetchInto(AccountContact.class);public static RecordMapper<Record, AccountContact> getAccountRecordMapper() { return new RecordMapper< Record, AccountContact>() { @Override public AccountContact map(Record record) { AccountContact ac = new AccountContact(); ac.setName(record.getValue("NAME")); ac.setFistname(record.getValue("FIRSTNAME")); ac.setLastname(record.getValue("LASTNAME")); return ac; } }; }public static RecordMapper<Record, AccountContact> getAccountRecordMapper() { return new RecordMapper< Record, AccountContact>() { @Override public AccountContact map(Record record) { AccountContact ac = new AccountContact(); ac.setName(record.getValue(a.NAME)); ac.setFistname(record.getValue(c.FIRSTNAME)); ac.setLastname(record.getValue(c.LASTNAME)); return ac; } }; }public static RecordMapper<Record, AccountContact> getAccountRecordMapper() { return new RecordMapper< Record, AccountContact>() { @Override public AccountContact map(Record record) {
TAccount a = new TAccount();
TContact c = new TContact(); AccountContact ac = new AccountContact(); ac.setName(record.getValue(a.NAME)); ac.setFistname(record.getValue(c.FIRSTNAME)); ac.setLastname(record.getValue(c.LASTNAME)); return ac; } }; }
final TAccount a = new TAccount("a,"); final TContact c = new TContact("c"); List<AccountContact> list = create.select(a.NAME,c.FIRSTNAME, c.LASTNAME).from(a.leftOuterJoin(c).on(a.ID.eq(c.ACCOUNTID))).fetch(new RecordMapper< Record, AccountContact>() { @Override public AccountContactmap(Record record) { AccountContactac = new AccountContact(); ac.setName(record.getValue(a.NAME)); ac.setFirstname(record.getValue(c.FIRSTNAME)); ac.setLastname(record.getValue(c.LASTNAME)); return ac; } });Hi Lukas,jooq will not only be suitable for creating typesafe sql queries but also for code validation. in the past i randomly ran into sql exceptions caused by non existing columns, tables which have been just forgotten to change. jooq provides a good way,to instantly see validation errors if anything on the table schema changed. that way i could improve the code to become more stable, even in the darkest corners.
a plus will also be to reduce the amount of code necessary to query and build the entities for my model. on half will be the query which i already tested successfully and works for me very well, the other half is to put the result of a query into any
kind of pojo, no matter what type it will be, single or joined table row representations. This is the part which gives me headaches.i understood now that jooq is purely from the sql point of view, which does not really care about my problematic second half.maybe my ultimate goal gets more clear with this example, though i mean its the latter you mentioned on your last reply:But I'm afraid that it might be trying to re-normalise flattened result sets, that have been denormalised by random joins. In that case, I don't think there will be a reliable solution.