0

I would like to be updated in the database only those fields that are specified in the form. In entity "account" I use annotation @DynamicUpdate.

Class AccountMB (@RequestScoped) with methods:

public String update() {
    getDao().update(getInstance());
    return SUCCESS;
}

public Account getInstance() {

    //setId(new Long("1"));

    if (instance == null) {
        if (id != null) {
            instance = loadInstance();
        } else {
            instance = createInstance();
        }
    }

    return instance;
}

And form form.xhtml:

<f:metadata>
    <f:viewParam name="accountId" value="#{accountMB.id}" />
</f:metadata>

<h:form prependId="false">

    <h:inputHidden id="accountId" value="#{accountMB.id}"/>

    <h:inputHidden id="id" value="#{accountMB.instance.id}"/>

    <h:inputText id="firstName" value="#{accountMB.instance.firstName}"/>

    <h:commandButton type="submit" action="#{accountMB.update}" value="Save">
        <f:setPropertyActionListener target="#{accountMB.id}" value="1" />
    </h:commandButton> 
</h:form>

I open page form.xhtml?accountId=1, in the form of loaded data, click to "Save". It writes an error:

java.sql.SQLException: ORA-01407: cannot update ("MYBD"."ACCOUNTS"."EMAIL") to NULL

If in getInstance() method uncomment setId(new Long("1"));, the data is saved.

And if I use annotation @ViewScoped in AccountMB, the data is saved.

But I want to use annotation @RequestScoped.

I understand, I triggered createInstance(); and email field is not filled.

Tell me how to pass id to load method loadInstance();.

I use <f:setPropertyActionListener target="#{accountMB.id}" value="1" /> and <h:inputHidden id="accountId" value="#{accountMB.id}"/>. But it is not work. Please help me.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555

1 Answers1

0

Your mistake is that you're (lazy) loading the entity in the getter method instead of the @PostConstruct. The entity is being loaded/created before JSF was able to call setId(). In any case, doing business logic in a getter method is alarming. You'd better not do that and keep the getter methods untouched.

As you want to use a @RequestScoped bean, the <f:viewParam> isn't terribly useful to you. It would be too late to prepare the entity in the @PostConstruct, so that it could be filled with submitted values. It would work just fine with a @ViewScoped bean as it's being reused on postback.

In the @RequestScoped bean you need to grab the HTTP request parameter yourself:

@Named
@RequestScoped
public class AccountBacking {

    private Account account;

    @EJB
    private AccountService service;

    @PostConstruct
    public void init() {
        String id = FacesContext.getCurrentInstance().getRequestParameterMap().get("accountId");
        account = (id != null) ? service.find(Long.valueOf(id)) : new Account();
    }

    public void save() {
        service.save(account);
    }

    public Account getAccount() {
        return account;
    }

}

Then you can get away with this form, whereby just <f:param> is being used to retain the GET parameter on postbacks:

<h:form>
    <h:inputText id="firstName" value="#{accountBacking.account.firstName}"/>

    <h:commandButton action="#{accountBacking.save}" value="Save">
        <f:param name="accountId" value="#{param.accountId}" />
    </h:commandButton>
</h:form>
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555