2014-09-05 2 views
7

Dans mon projet de printemps en cours, mes formes sont à mettre en œuvre une structure comme celle-ci:erreur lorsqu'un formulaire avec un champ de sélection est soumis

<form class="form" id="Pagina" role="form" method="POST" action="/loja/Pagina/cadastra" enctype="multipart/form-data"> 
... 
</form> 

et il est traité dans le serveur par ce methos:

contrôleur

@RequestMapping(value="cadastra", method=RequestMethod.POST) 
@ResponseBody 
@ResponseStatus(HttpStatus.CREATED) 
public E cadastra(@ModelAttribute("object") E object, BindingResult result, @RequestParam(value="file", required=false) MultipartFile file, @RequestParam(value="icone", required=false) MultipartFile icone, @RequestParam(value="screenshot", required=false) MultipartFile screenshot[]) throws Exception { 
    E ret = serv.cadastra(object, file, icone, screenshot); 
    if (ret != null) 
     return ret; 
    else 
     throw new Exception(); 
} 

Service

regarde à l'intérieur comme

@OneToOne(fetch = FetchType.EAGER) 
@JoinColumn(name="pagina_mae", nullable = true) 
@Order(value=5) 
@Select(name="pagina", ordem = 5) 
@Sidebar 
private Pagina pagina; 

@OneToOne(fetch = FetchType.EAGER) 
@JoinColumn(name="produto_mae", nullable = true) 
@Order(value=6) 
@Select(name="produto", ordem = 6) 
@Sidebar 
private Produto produto; 

Si les options ceci:

@PreAuthorize("hasPermission(#user, 'cadastra_'+#this.this.name)") 
@Transactional 
public E cadastra(E e, MultipartFile file, MultipartFile icone, MultipartFile[] screenshot) { 
    return dao.persist(e); 
} 

Mon problème, il est quand la forme ont un champ comme celui-ci:

<label>pagina</label> 
<select name="pagina.id" class="form-control select" data-lista="/loja/Pagina/listagem.json"> 
... 
</select> 

<label>produto</label> 
<select name="produto.id" class="form-control select" data-lista="/loja/Produto/listagem.json"> 
... 
</select> 

qui associe un atribute comme celui-ci dans la classe entiy :

<option value="">.</option> 
<option value="...">...</option> 

Si je soumets le formulaire avec l'option vide sélectionnée, Je reçois cette erreur:

object references an unsaved transient instance - save the transient instance before flushing: com.spring.loja.model.pagina.persistence.model.Pagina; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.spring.loja.model.pagina.persistence.model.Pagina 

mais si, par exemple, insérer un enregistrement manuellement dans la base de données (dans mon cas, en utilisant pgAdmin3) et sélectionnez cet élément dans la sélection, le formulaire est soumis sans erreurs. Tout le monde peut me dire comment je corrige cela, pour me permettre de soumettre le formulaire avec ou sans les données sélectionnées de <select>.

UPDATE

Code

pour la classe Pagina:

@Entity 
@Table(name="pagina") 
@MainForm(grupo = 2, icone = "file") 
public class Pagina extends ModelEntity { 

    @Id 
    @Column(name = "id") 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private Integer id; 

    @Column(name = "nome", unique = true) 
    @Order(value=1) 
    @Input(type="hidden", name="nome", ordem = 1) 
    private String nome; 

    @Column(name = "titulo", nullable = false) 
    @Order(value=2) 
    @Input(name="titulo", ordem = 2) 
    private String titulo; 

    @Column(name = "descricao", length=65535) 
    @Order(value=4) 
    @Textarea(name="descricao", ordem = 4) 
    private String descricao; 

    @OneToOne(fetch = FetchType.EAGER) 
    @JoinColumn(name="pagina_mae", nullable = true) 
    @Order(value=5) 
    @Select(name="pagina", ordem = 5) 
    @Sidebar 
    private Pagina pagina; 

    @OneToOne(fetch = FetchType.EAGER) 
    @JoinColumn(name="produto_mae", nullable = true) 
    @Order(value=6) 
    @Select(name="produto", ordem = 6) 
    @Sidebar 
    private Produto produto; 
} 

UPDATE 2

PaginaEditor.java

@Component 
public class PaginaEditor extends PropertyEditorSupport { 

    @Inject 
    private PaginaService paginaService; 

    @Override 
    public void setAsText(String text) { 
     if (!text.isEmpty()) { 
      Pagina pagina = paginaService.getObject(text); 
      setValue(pagina); 
     } 
    } 

} 

procédé ajouté à mon contrôleur:

@InitBinder 
public void initBinder(WebDataBinder binder) { 
    binder.registerCustomEditor(Pagina.class, new PaginaEditor()); 
} 
+0

c'est un problème ORM. Devinez Hibernate? Si vous ajoutez une étiquette pour l'ORM que vous utilisez, vous aurez beaucoup plus de chances de trouver de l'aide. Consultez également cette question/awnser http://stackoverflow.com/questions/2302802/object-references-an-unsaved-transient-instance-save-the-transient-instance-be –

+0

pouvez-vous s'il vous plaît nous montrer le code pour dao. persister (e); comment persistez-vous exactement, comme je pense peut-être que je sais ce que le problème est ici. – Aeseir

+0

@ug_ J'ai vu le lien, mais si j'essaie de suivre la suggestion (basiquement, c'est l'option 'cascade'), l'application essaie d'insérer un nouveau Pagina ou Produto et de l'associer à la Pagina que j'insère. –

Répondre

5

Les sélections sont difficiles dans Spring MVC.

Je pense que votre problème est que lorsque votre entité principale arrive à la couche de données à persister, la relation n'est pas là. Essayez de déboguer et de vérifier si l'affirmation ci-dessus est vraie.

Il y a deux façons d'obtenir ce tri.

Supposons une relation Société/Contact dans un système de contacts. Une entreprise a de nombreux contacts et un contact a une entreprise.

Extrait de l'entreprise.

// package declaration imports and all 
@Entity 
@Table(name = "company") 
public class Company { 

    private String name; 

    @OneToMany(mappedBy = "company") 
    private List<Contact> contacts = new ArrayList<Contact>(); 

    // getter and setters and any extra stuff you fancy putting here 

} 

Contactez-extrait

// package declaration imports and all 
@Entity 
@Table(name = "contact") 
public class Contact { 

    private String name; 

    @ManyToOne 
    private Company company; 

    // getter and setters and any extra stuff you fancy putting here 

} 

Et un extrait de jsp avec la sélection. Nous supposons qu'il existe un objet "contact" et une liste de clients dans le modèle.

<form:form modelAttribute="contact"> 
    <form:input path="name" /> 
    <form:select path="customer" items="${customers}" itemValue="id" itemLabel="name" /> 
</form:form> 

Avec ce code en place, vous pouvez utiliser un PropertyEditor comme ceci.

@Component 
public class CustomerEditor extends PropertyEditorSupport { 

    @Inject 
    private CustomerService customerService; 

    @Override 
    public void setAsText(String text) { 
     if (StringUtils.isNotBlank(text)) { 
      Customer customer = this.customerService.findById(Integer 
        .valueOf(text)); 
      this.setValue(customer); 
     } 
    } 

} 

et inscrivez-vous dans votre Spring Context comme ceci.

@InitBinder 
public void initBinder(WebDataBinder binder) { 
    binder.registerCustomEditor(Customer.class, this.customerEditor); 
} 

Qu'est-ce qui se passe ici est que, chaque fois que Spring trouve un objet de type client, il utilisera le PropertyEditor pour convertir le (dans ce cas) Id à l'objet et par le type du contact (dans ce cas) arrive à la couche de données (Hibernate), l'entité Client appropriée attendra aussi heureux que Larry.

C'est une façon automagique de le faire.

Une autre façon de le faire est de créer un formulaire/DTO ou tout ce que vous souhaitez appeler et ajouter les champs, y compris un champ customerId (dans ce cas) et de vous convertir avant de sauvegarder votre entité.

J'espère que je compris votre problème droit parce qu'il m'a fallu quelques minutes pour écrire ce ... :)

+0

Je pense que cela fonctionnera –

+0

Ok, je comprends les bases de votre réponse, mais j'ai quelques questions: 1) quelle est la bibliothèque du composant StringUtils? Quand j'ajoute ceci dans mon application, l'éclipse donne plusieurs options. 2) Où dois-je placer la classe dérivée de 'PropertyEditorSupport'? 3) Où dois-je placer la méthode 'initBinder'? –

+1

@KleberMota StringUtils provient d'apache commons ie https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html –

Questions connexes