arnaudroger / SimpleFlatMapper

Fast and Easy mapping from database and csv to POJO. A java micro ORM, lightweight alternative to iBatis and Hibernate. Fast Csv Parser and Csv Mapper
http://simpleflatmapper.org
MIT License
437 stars 76 forks source link

How to add custom mapping for SqlParameterSourceFactory #675

Closed dicksonleong closed 5 years ago

dicksonleong commented 5 years ago

Hi, it's me again. Last time i tried to map Database column to Enum and it works, but now I want to map back Enum (implemented a common interface) back to database column (Int type) using SqlParameterSourceFactory.. But I can't find any documentation on this. Can you help?

arnaudroger commented 5 years ago

sure will have a look later today.

arnaudroger commented 5 years ago

so checked, there is the possibility to add an IndexedSetterProperty on a column

            Crud<FooInet, Long> crud =
                    JdbcMapperFactory
                        .newInstance()
                            .addColumnProperty("b", IndexedSetterProperty.<InetAddress>of((ps, i, t) -> ps.setObject(i, t.getHostAddress(), Types.OTHER)))
                            .crud(FooInet.class, long.class)
                            .table(c, "issue_649");

https://github.com/arnaudroger/SimpleFlatMapper/blob/89fe8bd881b21648acfb86c85c54e4d9a09f6978/sfm-jdbc/src/test/java/org/simpleflatmapper/jdbc/test/Issue649Test.java#L32

I think that should solve your problem it's not as nice as the getter side, butI'll try to add a addSetter for type in the next release

dicksonleong commented 5 years ago

I tried with SqlParameterSourceFactory but it doesn't seems like working, did I do something wrong?

private val sourceFactory = JdbcTemplateMapperFactory.newInstance()
        .addColumnProperty("status", IndexedSetterProperty.of<Status> { ps, i, value ->
            ps.setInt(i, value.persistValue) // this line doesn't trigger on breakpoint
        })
        .newSqlParameterSourceFactory(MyEntity::class.java)
sourceFactory.newSqlParameterSource(myEntity).getValue("status") // => Status
arnaudroger commented 5 years ago

no I digged a bit deeper, and realized it was not going through what I thought it would. Right now I don't believe there is a way to do that, will make it possible.

arnaudroger commented 5 years ago

so first try I was thinking of adding a ConverterProperty like

 SqlParameterSourceFactory<Issue675> sourceFactory = JdbcTemplateMapperFactory.newInstance()
                .addColumnProperty("myEnum", new ConverterProperty<MyEnum, Long>(new ContextualConverter<MyEnum, Long>() {
                    @Override
                    public Long convert(MyEnum in, Context context) throws Exception {
                        switch (in) {
                            case ONE: return 1l;
                            case TWO: return 2l;
                            default: throw new IllegalArgumentException();
                        }
                    }
                }, MyEnum.class))
                .newSqlParameterSourceFactory(Issue675.class, query);

see https://github.com/arnaudroger/SimpleFlatMapper/commit/e6a9f6eb25e0f23ebc29627d5fa39a9683256339#diff-1c54faed1327f4ec187e9716727c0945R18

it's a bit awkward because the parameter source is not directly link to the preparedstatement so it can't go through the setterproperty, and the getterproperty is about the result set. what do you think?

dicksonleong commented 5 years ago

Looks okay.. but is it possible to specify a "global" converter like the one you suggested in here?

arnaudroger commented 5 years ago

by global you mean link to the type instead of the column? yes so it should work as it check the convert type so if you apply ot all column

.addColumnProperty(k -> true, new ConverterProperty<MyEnum, Long>(new ContextualConverter<MyEnum, Long>() {
                    @Override
                    public Long convert(MyEnum in, Context context) throws Exception {
                        switch (in) {
                            case ONE: return 1l;
                            case TWO: return 2l;
                            default: throw new IllegalArgumentException();
                        }
                    }
                }, MyEnum.class))

it should apply to all MyEnum.class