GithubHelp home page GithubHelp logo

Generic Dao Iciql implementation about iciql HOT 16 CLOSED

gitblit avatar gitblit commented on September 6, 2024
Generic Dao Iciql implementation

from iciql.

Comments (16)

decebals avatar decebals commented on September 6, 2024

I can implement the simple List<T> findAll() method.

I see this line in examples:

// select * from products
List<Product> allProducts = db.from(p).select();

but I don't know what is p and in my generic context (<T>) how can I create a such object.

from iciql.

gitblit avatar gitblit commented on September 6, 2024

DAOs are (currently) interfaces with annotated methods.

public interface CustomerDao extends Dao {
    @SqlQuery("select * from customers where email = :email")
    public Customer findByEmail(String email);
}

Db db.open(url, username, password);
CustomerDao dao = db.open(DbCustomerDao.class);
Customer customer = dao.findByEmail("[email protected]");

On your other example...

Product productsTable = new Product();
List<Product> allProducts = db.from(productsTable).select();

Iciql is heavily reflection-driven. Reviewing the documentation @ http://iciql.com might be helpful.

from iciql.

gitblit avatar gitblit commented on September 6, 2024

That example requires Java 8 with -parameters flag (sound familiar? ;) ). Java 7 alternative would be:

 @SqlQuery("select * from customers where email = :1")

OR

@SqlQuery("select * from customers where email = :email")
public Customer findByEmail(@BindBean("email") String email);

from iciql.

gitblit avatar gitblit commented on September 6, 2024

The section on aliases might be helpful in understanding what p is in your question:
http://iciql.com/usage.html#H16

from iciql.

decebals avatar decebals commented on September 6, 2024
  • Is it ok this implementation?
public T findById(ID id) {
    T alias = getAlias();

    return (alias != null) ? db.from(alias).where(alias.getId()).is(id).selectFirst() : null;
}

because I received an error:

Exception in thread "main" com.iciql.IciqlException: unmapped field in statement!
SELECT id, name, fiscalCode FROM Company WHERE ? = ? 
  • Other problem:
@Iciql.IQTable
public class Company extends Entity {

    @Iciql.IQColumn
    private String name;

    @Iciql.IQColumn
    private String fiscalCode; // CUI or CIF

    // getters and setters
}

public abstract class Entity implements Identifiable<Long> {

    @Iciql.IQColumn(primaryKey = true, autoIncrement = true)
    protected Long id;

    // getters and setters
}

with this code:

companyDao.save(new Company().setName("test").setFiscalCode("1"));
db.merge(entity);

give me an exception:

java.lang.IllegalStateException: No primary key columns defined for table class ro.fortsoft.matilda.domain.Company - no update possible

from iciql.

gitblit avatar gitblit commented on September 6, 2024
public T findById(ID id) {
    return ... where(alias.getId()).is(id) ...
}

This would only work if you are using a custom TypeAdapter on the ID type and TBH it's not a use-case I've needed so I'm not sure if it will work. I always use ints, longs, or UUIDs for identifiers.

On your other problem you need to...

@Iciql.IQTable(inheritColumns = true)
public class Company extends Entity {

from iciql.

gitblit avatar gitblit commented on September 6, 2024

Actually, the custom ID type should work just fine. It's basically the same as an UUID case which I currently handle with a custom TypeAdapter..

from iciql.

decebals avatar decebals commented on September 6, 2024

It's ok for now. I made some progress but now I have another problem.

I try to implement a findByExample. The implementation is ok in InMemory and Csv and I wish to preserve this method for Iciql.

Map<String, Method> getters = BeanUtils.findGetters(example);
Map<String, Object> exampleProperties = BeanUtils.getProperties(example, getters);

T alias = getAlias();
Query<T> query = getDb().from(alias);
for (Map.Entry<String, Object> property : exampleProperties.entrySet()) {
    String propertyName = property.getKey();
    Object propertyValue = property.getValue();
    // >> WHERE (companyId = 1 AND name = 'IBM')
//    query.where(propertyName, propertyValue); // << HERE
}
System.out.println("query = " + query.toSQL());

return query.select();

My problem is that I don't know how I create the where clause in Iciql.
Can you help me?

from iciql.

gitblit avatar gitblit commented on September 6, 2024

Best-match (I think) for your approach:

List<String> clauses = new ArrayList<>();
List<Object> parameters = new ArrayList<>();
for (Map.Entry<String, Object> property : exampleProperties.entrySet()) {
    String propertyName = property.getKey();
    clauses.add(propertyName + "=?");
    parameters.add(property.getValue());
}
String clause = Joiner.on(" AND ").join(clauses);
List<T> list = db.from(alias).where(clause, parameters).select();
return list;

from iciql.

gitblit avatar gitblit commented on September 6, 2024

Actually that could be written more succinctly - but I think you get the general idea.

from iciql.

gitblit avatar gitblit commented on September 6, 2024

Something like this is cleaner although the values() bit is still clunky but that's because Iciql does not accept a Collection.

Object [] parameters = exampleProperties.values().toArray();
String clause = exampleProperties.keySet().stream()
    .map(name -> name + "=?")
    .collect(Collectors.joining(" AND "));
return db.from(alias).where(clause, parameters).select();

from iciql.

decebals avatar decebals commented on September 6, 2024

Brilliant. I am almost ready 😄

Maybe the last issue is the non generic dao methods (findByXYZ).

For example:

public interface CustomerDao extends EntityDao<Customer> {

    public Customer findByEmail(String email);

}

public class IciqlCustomerDao extends IciqlEntityDao<Customer> implements CustomerDao {

    public Customer findByEmail(String email) {
        // HERE annotation or an elegant/simple code
    }

}

My actual implementation is:

public class IciqlCustomerDao extends IciqlDao<Customer> implements CustomerDao {

    @Override
    public Customer findByEmail(String email) {
        Customer alias = getAlias();

        return getDb().from(alias).where(alias.getEmailAddress()).is(email).selectFirst();
   }

}

I don't know if I can use annotations (SqlStatement, ...) for a more simple, declarative approach.
For now in Iciql a generic MyDao must extends Dao and for my purpose I want to extends EntityDao. I see in JDBI that is not a such constrain. If I want to use the default (Generic)Dao provided by iciql then fine, I will extends that interface but I'd rather not have this constraint.
In this scenario my IciqlDao must be something like DaoProxy from iciql, maybe help me if actual DaoProxy is spited in two: BaseDaoProxy and CrudDaoProxy (or other better names) then my IciqlDao extends BaseDaoProxy.

I must recognize that the current workflow from iciql is straightforward and it's very simple to use this library in a web application developed with Pippo web framework but I wish to push the things ahead.

I implemented with success in my pippo based application the open session in view pattern using a generic dao and iciql.

The core class is:

public class DbUtils {

    private static final Logger log = LoggerFactory.getLogger(DbUtils.class);

//    private static final String url = "jdbc:h2:mem:matilda";
    private static final String url = "jdbc:h2:./data/matilda";
    private static final String username = "";
    private static final String password = "";

    private static DataSource dataSource;
    private static Db genericDb;
    private static Map<Request, Db> cache = new ConcurrentHashMap<>();

    static {
        dataSource = JdbcConnectionPool.create(url, username, password);
    }

    public static Db getDb() {
        Request request = getRequest();
        if (request == null) {
            if (genericDb == null) {
                log.debug("Create generic Db instance");
                genericDb = Db.open(dataSource);
            }

            return genericDb;
        }

        if (!cache.containsKey(request)) {
            log.debug("Create request Db instance");
            cache.put(request, Db.open(dataSource));
        }

        return cache.get(request);
    }

    public static void closeDb() {
        Request request = getRequest();
        if (request == null) {
            if (genericDb != null) {
                log.debug("Close generic Db instance");
                genericDb.close();
            }
        } else if (cache.containsKey(request)) {
            log.debug("Close request Db instance");
            cache.remove(request).close();
        }
    }

    private static Request getRequest() {
        // TODO fix this in pippo
//        return Request.get();
        RouteContext routeContext = RouteDispatcher.getRouteContext();

        return (routeContext != null) ? routeContext.getRequest() : null;
    }

}

and in my base iciql dao (this class is extended by all my dao classes):

public class IciqlDao<T extends Entity> extends IciqlEntityDao<T> {

    public IciqlDao() {
        this(DbUtils::getDb);
    }

    // I use this constructor in DaoTest class (use in memory h2)
    public IciqlDao(IciqlDbFactory dbFactory) {
        super(dbFactory);
    }

}

all I do in my PippoApplication class is to add an after filter that calls DbUtils.closeDb()

It is an experimental approach and the result (the generic-dao library with inmemory, csv, iciql implementations as modules, plus the real application) will be available as open source projects when I finished the work.

from iciql.

gitblit avatar gitblit commented on September 6, 2024

For now in Iciql a generic MyDao must extends Dao and for my purpose I want to extends EntityDao.

The way the Iciql DAO feature is implemented you can not provide a Class you can only provide an Interface and your interface must extend Dao. Your class hierarchy is incompatible with the current DAO feature. I'm open to refactoring DaoProxy to be more useful but for now I think you are stuck with the DSL approach for findByEmail.

from iciql.

decebals avatar decebals commented on September 6, 2024

I pushed a first commit of my tiny generic dao project. The iciql implementation is here. Sure is not perfect but it's a start.
I see that I have a problem with iciql repository. Maybe it's time to upload it on sonatype 😄

from iciql.

decebals avatar decebals commented on September 6, 2024

Thanks for your support!

from iciql.

gitblit avatar gitblit commented on September 6, 2024

Iciql will get to MavenCentral eventually. It's on my todo list, low on my list, but on the list nontheless.

I think the main problem you have is that you didn't specify the Iciql repo in the POM.

from iciql.

Related Issues (18)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.