LazyQueryContainer with own QueryFactory

Hello,

I’ve got a database table with no foreign keys to related tables. But I need to show the related information, so I decided to create an own Query and QuertFactory for LazyQueryContainer.
(There are more than 10000 rows in source table.)

Here’s my code, the QueryFactory:

import javax.persistence.EntityManager;
import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
import org.vaadin.addons.lazyquerycontainer.QueryFactory;

public class AuditlogsExtQueryFactory implements QueryFactory {

    private EntityManager entityManager;
    private QueryDefinition definition;

    public AuditlogsExtQueryFactory(EntityManager entityManager) {
        super();
        this.entityManager = entityManager;
    }

    public void setQueryDefinition(QueryDefinition definition) {
        this.definition = definition;
    }

    @Override
    public Query constructQuery(QueryDefinition qd) {
        return new AuditlogsExtQuery(entityManager, definition, new Object {"id"}, new boolean {true} );
    }
}

And the Query:

import com.vaadin.data.Item;
import com.vaadin.data.util.BeanItem;
import javax.persistence.EntityManager;
import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
[...]


public class AuditlogsExtQuery implements Query {

    private EntityManager entityManager;
    private QueryDefinition definition; // not used
    private String criteria = "";
    private ConverterUtils<AuditlogsExt> converterUtils;
    private String rowPropertyMap;

    public AuditlogsExtQuery(EntityManager entityManager, QueryDefinition definition,
            Object sortPropertyIds, boolean sortStates) {
        super();
        System.out.println("init");
        this.entityManager = entityManager;
        this.definition = definition;
        this.converterUtils = new ConverterUtils<>();
        this.rowPropertyMap = new String {"id", "event", "source", "target", "clientInfo"};
       
        for (int i = 0; i < sortPropertyIds.length; i++) {
            if (i == 0) {
                criteria = " ORDER BY";
            } else {
                criteria += ",";
            }
            criteria += " a." + sortPropertyIds[i]
;
            if (sortStates[i]
) {
                criteria += " ASC";
            } else {
                criteria += " DESC";
            }
        }
    }
    
    @Override
    public int size() {
        System.out.println("size");
        return this.entityManager.createQuery("SELECT count(a) FROM Auditlogs a WHERE a.validto > CURRENT_DATE", Long.class)
                .getSingleResult()
                .intValue();
    }

    @Override
    public List<Item> loadItems(int startIndex, int count) {
        System.out.println("loaditems - startIndex: " + startIndex + " - count: " + count);
        javax.persistence.Query query = entityManager.createQuery("SELECT a.id, a.event, a.source, a.target, a.clientInfo FROM Auditlogs a JOIN Users u ON a.usersId = u.id WHERE a.validto > CURRENT_DATE " + criteria);
        query.setFirstResult(startIndex);
        query.setMaxResults(count);

        List<Object> result = query.getResultList();
        // need to convert Object to real entity - use BeanUtils - is it a good solution???
        List<AuditlogsExt> resultExt = this.converterUtils.convertToEntityList(AuditlogsExt.class, result, this.rowPropertyMap);
        List<Item> items = new ArrayList<Item>();
        for (AuditlogsExt alext : resultExt) {
            BeanItem bi = new BeanItem<AuditlogsExt>(alext);
            items.add(bi);
        }

        return items;
    }

    @Override
    public void saveItems(List<Item> addedItems, List<Item> modifiedItems, List<Item> removedItems) {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public boolean deleteAllItems() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public Item constructItem() {
        return new BeanItem<AuditlogsExt>(new AuditlogsExt());
    }

}
[/i]
[/i]

[i]
[i]
Ok, let’s use it:

[...]

LazyQueryContainer logs = new LazyQueryContainer(new AuditlogsExtQueryFactory(auditlogsService.getEntityManager()), "id", 50, true);
        
logs.addContainerProperty("id", Long.class, 0L, true, true);
logs.addContainerProperty("event", String.class, "", true, true);

Grid grid = new Grid();
grid.setContainerDataSource(logs);
[...]

The grid is shown with some data, but then I gave a big, fat exception (console log):

[...]

init
size
loaditems - startIndex: 0 - count: 50
loaditems - startIndex: 50 - count: 50
loaditems - startIndex: 100 - count: 50
ápr. 19, 2016 12:54:07 DU com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
java.lang.RuntimeException: Unable to get item id for index: 123 from container using Container.Indexed#getIdByIndex() even though container.size() > endIndex. Returned item id was null. Check your container implementation!
    at com.vaadin.data.ContainerHelpers.getItemIdsUsingGetIdByIndex(ContainerHelpers.java:90)
    at org.vaadin.addons.lazyquerycontainer.LazyQueryContainer.getItemIds(LazyQueryContainer.java:655)
    at com.vaadin.server.communication.data.RpcDataProviderExtension.pushRowData(RpcDataProviderExtension.java:367)
    at com.vaadin.server.communication.data.RpcDataProviderExtension.access$900(RpcDataProviderExtension.java:65)
    at com.vaadin.server.communication.data.RpcDataProviderExtension$2.requestRows(RpcDataProviderExtension.java:293)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:158)
    at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:118)
[...]

What did I do wrong?
And what is there a better way to select from a “no foreign key table”?

[/i]
[/i]

Ok, this is the second times I answerd my own question. :slight_smile: Tradition. :slight_smile:
(It’s not because I’m so smart. On the contrary.)
But I leave this posts in the forum, because it - maybe - will be useful someone.
Ok, this NOT the whole solution for my original problem… The “solution” is generated an other (similar) exception.
So finally I modified my code which is resolved my problem (the Query - I marked new or modified lines with this: //@CHANGED):

[code]
public class AuditlogsExtQuery implements Query {

private EntityManager entityManager;
private QueryDefinition definition; // not used
private String criteria = "";
private ConverterUtils<AuditlogsExt> converterUtils;
private String rowPropertyMap;
[color=#B22222]

private Long startId; //@CHANGED
[/color]

public AuditlogsExtQuery(EntityManager entityManager, QueryDefinition definition,
        Object sortPropertyIds, boolean sortStates) {
    super();
    System.out.println("init");
    this.entityManager = entityManager;
    this.definition = definition;
    this.converterUtils = new ConverterUtils<>();
    this.rowPropertyMap = new String{"id", "event", "source", "target", "clientInfo"};
    [color=#B22222]

this.startId = getMaxId(); //@CHANGED
[/color]

    for (int i = 0; i < sortPropertyIds.length; i++) {
        if (i == 0) {
            criteria = " ORDER BY";
        } else {
            criteria += ",";
        }
        criteria += " a." + sortPropertyIds[i]

;
if (sortStates[i]
) {
criteria += " ASC";
} else {
criteria += " DESC";
}
}
}

@Override
public int size() {
    System.out.println("size");
    return this.entityManager.createQuery("SELECT count(a) FROM Auditlogs a WHERE a.validto > CURRENT_DATE", Long.class)
            .getSingleResult()
            .intValue();
}

@Override
public List<Item> loadItems(int startIndex, int count) {
    System.out.println("loaditems - startIndex: " + startIndex + " - count: " + count);
    javax.persistence.Query query = entityManager.createQuery("SELECT a.id, a.event, a.source, a.target, a.clientInfo FROM Auditlogs a JOIN Users u ON a.usersId = u.id WHERE a.validto > CURRENT_DATE " + criteria);
    query.setFirstResult(startIndex);
    query.setMaxResults(count);

    List<Object> result = query.getResultList();
    List<AuditlogsExt> resultExt = this.converterUtils.convertToEntityList(AuditlogsExt.class, result, this.rowPropertyMap);
    List<Item> items = new ArrayList<Item>();
    for (AuditlogsExt alext : resultExt) {
        BeanItem bi = new BeanItem<AuditlogsExt>(alext);
        items.add(bi);
    }

    return items;
}

@Override
public void saveItems(List<Item> addedItems, List<Item> modifiedItems, List<Item> removedItems) {
    throw new UnsupportedOperationException("Not supported.");
}

@Override
public boolean deleteAllItems() {
    throw new UnsupportedOperationException("Not supported.");
}

@Override
public Item constructItem() {
    //System.out.println("constructItem");
    [color=#B22222]

return new BeanItem(new AuditlogsExt(this.startId++)); //@CHANGED
[/color]
}


private Long getMaxId() { //@CHANGED
return this.entityManager.createQuery(“SELECT MAX(a.id) FROM Auditlogs a”, Long.class)
.getSingleResult()
.longValue();
}

}
[/i]
[/i]
[/code][i]
[i]
The scroll down works prefectly.
BUT! When I scroll up to the top - after some page down - it gives me a fancy exception: :frowning:

[code]
[…]

loaditems - startIndex: 1050 - count: 50
loaditems - startIndex: 1100 - count: 50
loaditems - startIndex: 1150 - count: 50
loaditems - startIndex: 1200 - count: 50
loaditems - startIndex: 1250 - count: 50
loaditems - startIndex: 1300 - count: 50
loaditems - startIndex: 50 - count: 50
loaditems - startIndex: 100 - count: 50
ápr. 19, 2016 2:56:40 DU com.vaadin.server.DefaultErrorHandler doDefault
SEVERE:
java.lang.NullPointerException
at org.vaadin.addons.lazyquerycontainer.LazyIdList.get(LazyIdList.java:91)
at org.vaadin.addons.lazyquerycontainer.LazyQueryContainer.getIdByIndex(LazyQueryContainer.java:230)
at com.vaadin.data.ContainerHelpers.getItemIdsUsingGetIdByIndex(ContainerHelpers.java:88)
at org.vaadin.addons.lazyquerycontainer.LazyQueryContainer.getItemIds(LazyQueryContainer.java:655)
at com.vaadin.server.communication.data.RpcDataProviderExtension.pushRowData(RpcDataProviderExtension.java:367)
at com.vaadin.server.communication.data.RpcDataProviderExtension.access$900(RpcDataProviderExtension.java:65)
at com.vaadin.server.communication.data.RpcDataProviderExtension$2.requestRows(RpcDataProviderExtension.java:293)
at sun.reflect.GeneratedMethodAccessor60.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
[…]

[/code]So I ask - not just from myself :slight_smile: - What did I do wrong? :slight_smile:

[/i]
[/i]

I found the problem.
The main problem is the wrong select. There need OUTER JOIN select, because of some userId column is missing or consits false vale.

So the correct select is:

SELECT a.id, a.event, a.source, a.target, a.clientInfo, a.created, u.login as username FROM Auditlogs a LEFT OUTER JOIN Users u ON a.usersId = u.id