ListDataProvider refreshAll() does not update the grid

I could not figure out how to refresh the ListDataProvider from the backend when the underlying data in the database is changed (i.e. after deleting a row with repository.delete() the entry is deleted from the mysql db, or changing a row manually through mysql console) dataprovider.refreshAll() method does not update the grid.

What I am missing?

If I set the grid dataprovider to lazy load from the callbacks, there is no refresh problem, however the grid does not seem to correctly list all entries this time


UI;

    ....
    ListDataProvider<Account> ldp = DataProvider.ofCollection(service.findAll());
    grid.setDataProvider(ldp);
    ...
    // editing an entry works fine
    grid.getEditor().setEnabled(true).addSaveListener(e -> {
        Account bean = e.getBean();
        service.save(bean);
    });
    grid.getEditor().setBuffered(true);
    ...
    // refresh after deleting, or changing the entry in the DB directly does not update the grid
    getBtn_refresh().addClickListener( event -> ldp.refreshAll() );


Service;

@Stateless
// The service needs to be marked as LocalBean if it implements an interface otherwise we get the error
// WELD-001408: Unsatisfied dependencies for type with qualifiers @Default when implementing interface
// when the application is deployed
@LocalBean
public class AccountService implements AbstractService<Account> {
    @Inject AccountRepository repo;
    public AccountService() {};

    public Account save(Account entity) {
        return repo.save(entity);
    }

    public void delete(Account entity) {
        repo.delete(entity);
    }
 
    public int count() {
        return Math.toIntExact(repo.count());
    }

    public List<Account> findAll() {
        return repo.findAll();
    }

    public List<Account> findAllPaged(int offset, int limit) {
        int page = offset / limit;
        PageRequest pageRequest = new PageRequest(page, limit);
        return repo.findAll(pageRequest).getContent();
    }

    public List<Account> findAllPaged(int offset, int limit, Map<String, Boolean> sortOrders) {
        int page = offset / limit;
        List<Sort.Order> orders = sortOrders.entrySet().stream()
            .map(e -> new Sort.Order(e.getValue() ? Sort.Direction.ASC : Sort.Direction.DESC, e.getKey()))
            .collect(Collectors.toList());
        PageRequest pageRequest = new PageRequest(page, limit, orders.isEmpty() ? null : new Sort(orders));
        return repo.findAll(pageRequest).getContent();
    }

    public Account refreshEntry(Account entry) {
        return repo.findOne(entry.getId());
    }
}


Repository (Spring Data);

@Eager
public interface AccountRepository extends JpaRepository<Account, Long> {
}

Do you have a working equals() implementation on the entities?
This was causing me problems.

I have the following AbstractEntity class which all other entity classes extend from. Hence I believe equals() should not be the problem.

@MappedSuperclass
public abstract class AbstractEntity implements Serializable, Cloneable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(unique=true, nullable=false)
    private Long id;

    public Long getId() {
        return id;
    }

    protected void setId(Long id) {
        this.id = id;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if(this.id == null) {
            return false;
        }

        if (obj instanceof AbstractEntity && obj.getClass().equals(getClass())) {
            return this.id.equals(((AbstractEntity) obj).id);
        }

        return false;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 43 * hash + Objects.hashCode(this.id);
        return hash;
    }
}

equals() probably is the problem here. If you persist your entity to the database, your entity id stays the same, but you get a new object in return. Your equals method returns true for those two different objects, and so the grid doesn’t get updated.

Try debugging the equals method when dataprovider.refreshAll() is called.

Hi innodron,

To me the example looks like you’re using a snapshot of data (
service.findAll()
) and store it in memory behind a
ListDataProvider
. Since you have a service that you use to access the backend data, I’d recommend looking at
DataProvider.fromCallback
. This method is used to create a
DataProvider
that will access your fetch and size methods when needed and the data will be more up to date. Also the
refreshAll
method will be quaranteed re-fetch from the backend. If you still want to keep on using data snapshots in memory, you can do
grid.setItems(service.findAll())
to repopulate the
Grid
with the most recent snapshot.

//Teemu