Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vaadin 8 Grid sorting doesn't work when using DataProvider

In Vaadin 8, sorting Grid rows is as simple as clicking the column header. This toggles the column between ascending and descending sorting as described here. This works when populating the Grid via grid.setItems() method.

However when using a DataProvider as the Grid data source, clicking the column header does not sort the rows.

There is documentation about sort orders described here with DataProviders but handles sort orders when there are multiple sorting requirements.

Is there an easy way to simply use the same default sorting behaviour that the Grid exhibits when populated with grid.setItems() for when we populate with grid.setDataProvider()?

like image 357
Shiri Avatar asked Mar 09 '23 03:03

Shiri


2 Answers

The answer is no and it wouldn't make much sense else. The grid.setItems method internally creates a ListDataProvider which is a an in-memory data provider. Because it holds all the data in a list, it can easily sort the data with a comparator (coming from the grid column definition or supplied to the list data provider). So, Vaadin can only help you with sorting when it is OK for you to hold all the data in memory. If you have huge amounts of rows (e.g. a million) this is inefficient because you have a lot memory and CPU consumption. This is where your custom data provider comes in.

The idea of DataProvider is to delegate the data retrieval to a backend system like a database. For example, SQL databases allow to specify an "ORDER BY" clause in the SQL query which you could use to sort data via the backend. The data base itself is very efficient regarding resource consumption, assuming you have the right indexes applied.

So what is your actual data source? Maybe you can share your data provider code you have done so far.

EDIT

Excerpt from ListDataProvider:

@Override
public Stream<T> fetch(Query<T, SerializablePredicate<T>> query) {
    Stream<T> stream = getFilteredStream(query);

    Optional<Comparator<T>> comparing = Stream
            .of(query.getInMemorySorting(), sortOrder)
            .filter(c -> c != null)
            .reduce((c1, c2) -> c1.thenComparing(c2));

    if (comparing.isPresent()) {
        stream = stream.sorted(comparing.get());
    }

    return stream.skip(query.getOffset()).limit(query.getLimit());
}

@Override
public int size(Query<T, SerializablePredicate<T>> query) {
    return (int) getFilteredStream(query).count();
}

To answer your questions from the comment: Yes, ListDataProvider does the sort as you can see in its source code. And with your SQL database: Yes, it is the preferred way.

like image 176
Steffen Harbich Avatar answered May 11 '23 09:05

Steffen Harbich


I had the same problem and i found the solution in the comentaries of the post

When creating new Grid<Foo>(), it's not the same as new Grid<Foo>(Foo.class).

The second one creates columns also with sortProperties based on provided class. When you define columns manualy, you should define also sortProperties.

grid.addColumn(Foo::getBar).setSortProperty("bar").setCaption("Bar");

like image 35
Laercio Junior Avatar answered May 11 '23 08:05

Laercio Junior