将父类转换为每个类层次结构的单个表中的子类

时间:2012-02-26 20:28:22

标签: spring hibernate

我正在尝试设置用户案例,其中我有一个通用表单,可以处理所有类型的UploadedFile用户上传。所以,这是我的设置:

@Entity(name="UploadedForm")
@Table(name="uploaded_file")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)
public class UploadedFile implements Serializable{

    /** 
     * 
     */
    private static final long serialVersionUID = -6810328674369487649L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    protected Long id;

    @Column(name="name")
    protected String name = null;

    @Column(name="bytes",unique=true)
    @Lob
    protected byte[] bytes;

    @Column(name="type",nullable=false, updatable=false, insertable=false)
    protected String type;


    @ManyToOne(fetch=FetchType.LAZY, targetEntity=User.class)
    @JoinColumn(name="user_id")
    protected User user;

    @Column(name="date_submitted")
    @Temporal(TemporalType.DATE)
    protected Date dateSubmitted;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Date getDateSubmitted() {
        return dateSubmitted;
    }
    public void setDateSubmitted(Date dateSubmitted) {
        this.dateSubmitted = dateSubmitted;
    }

    @PrePersist
    @PreUpdate
    public void populateDateSubmitted(){
        this.dateSubmitted = new java.sql.Date(new java.util.Date().getTime());
    }
    public byte[] getBytes() {
        return bytes;
    }
    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }
    public String getType() {
        return type;
    }

}


@Entity(name="Document")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue(value="Document")
public class DocumentFile extends UploadedFile {

    public void setDateSubmitted(Date dateSubmitted) {
        this.dateSubmitted = dateSubmitted;
    }

    @PrePersist
    @PreUpdate
    public void populateDateSubmitted(){
        this.dateSubmitted = new java.sql.Date(new java.util.Date().getTime());
    }
    public byte[] getBytes() {
        return bytes;
    }
    public void setBytes(byte[] bytes) {
        this.bytes = bytes;
    }
}


@RequestMapping( value="{type}",method=RequestMethod.GET )
    public String showForm(ModelMap model, @PathVariable("type") String type){
        UploadedFile form = null;
        if((model.get("FORM") == null)){
            if(type.equals("document")){
                form =  new DocumentFile();
            }
            else if( type.equals("image")){
                form =  new ImageFile();
            }
        }else{
            form = (UploadedFile)model.get("FORM");
            if(form.getClass() == DocumentFile.class)
                form = (DocumentFile)form;
            else if(form.getClass() == ImageFile.class)
                form = (ImageFile)form;
        }


        model.addAttribute("message", "Please select your file and hit submit.");

        model.addAttribute("FORM", form);

        model.addAttribute("type", type);

        return "upload_form";
    }
    @RequestMapping( method=RequestMethod.POST )
    public String processForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") UploadedFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{
        if(!result.hasErrors()){

            UploadedFile savedFile = null;

            try {
                // Find the currently logged in user.  There has to be a more eloquent way...
                String username = principal.getName();
                User user = uService.findByName(username);

                // Set the associated user to the UploadedFile
                form.setUser(user);

                if(type.equals("document"))
                    form = (DocumentFile)form;
                else if(type.equals("image"))
                    form = (ImageFile)form;

                // Persist the file
                savedFile = this.saveFile(form);
            } catch (Exception e) {

                FileSaveException fse =  new FileSaveException("Unable to save file: " + e.getMessage());

                fse.setStackTrace(e.getStackTrace());

                throw fse;

            }
            model.addAttribute("message", "SUCCESS!");
            model.addAttribute("FORM", savedFile);
            return "upload_success";

        }else{

            return "upload_form";

        }
    }

<%@ include file="/WEB-INF/views/includes.jsp" %>
<%@ page session="false" %>
<%@ include file="/WEB-INF/views/header.jsp" %>
<head>
<title>upload</title>
</head>
<body>
    <h1>Upload Stuff -</h1>
    ${message}
    <br />
    <br />

    <form:form commandName="FORM" action="/upload"
        enctype="multipart/form-data" method="POST">
        <input type="hidden" name="type" value="${ type }"/>
        <table>
            <tr>
                <td colspan="2" style="color: red;"><form:errors path="*"
                        cssStyle="color : red;" /> ${errors}</td>
            </tr>
            <tr>
                <td>Name :</td>
                <td>
                    <form:input type="text" path="name" />
                </td>
            </tr>
            <tr>
                <td>File:</td>
                <td>
                    <form:input type="file" path="bytes" />
                </td>
            </tr>
            <tr>
                <td colspan="2"><input type="submit" value="Upload File" />
                </td>
            </tr>
        </table>
    </form:form>
    <br />
    <a href="/">Go home</a>
</body>
<%@ include file="/WEB-INF/views/footer.jsp"%>

我得到的错误是:

  

无法将对象UploadedFile强制转换为DocumentFile

知道为什么吗?

更新:我发现了一种解决方法,即不传递UploadedFile,而是传递我实际想要保留的Concrete类。我还必须删除controller / service / dao方法,并为每个UploadedFile子项创建一个。似乎应该有更好的方法来做到这一点。请提出你的建议。先感谢您! :)

1 个答案:

答案 0 :(得分:0)

你的问题看起来更像是关于Spring而不是Hibernate。这样:

@ModelAttribute(value="FORM") UploadedFile form

Spring在转换传入请求时无法知道您希望它创建DocumentFile UploadedFile的{​​{1}}个实例。可以创建自己的ConversionService,但是为不同的表单创建不同的请求映射可能更容易。像

@RequestMapping(value="/post/uploadedfile", method=RequestMethod.POST )
public String processUploadedFileForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") UploadedFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{
...
}

@RequestMapping(value="/post/documentfile", method=RequestMethod.POST )
public String processDocumentFileForm(Model model, @RequestParam(value="type") String type, @ModelAttribute(value="FORM") DocumentFile form,BindingResult result, Principal principal) throws FileSaveException, Exception{
...
}