当前位置: 代码网 > it编程>编程语言>Java > Spring data JPA只查询部分字段问题及解决

Spring data JPA只查询部分字段问题及解决

2024年08月12日 Java 我要评论
背景在jpa查询中,有时只需要查部分字段,这时jpa repository查出的是map,无法映射到entity类。会提示错误:org.springframework.core.convert.con

背景

在jpa查询中,有时只需要查部分字段,这时jpa repository查出的是map,无法映射到entity类。

会提示错误:

org.springframework.core.convert.converternotfoundexception: 
no converter found capable of converting from type 
[org.springframework.data.jpa.repository.query.abstractjpaquery$tupleconverter$tuplebackedmap] to type

网上搜索有多种解决方案。这里列举一下。

经过验证,本人采取了第一种方案,证明是可行的。

jpa 2.1以上的解决办法

实体中增加named query和result map

@sqlresultsetmapping(name = "ebookinfo",
        classes = @constructorresult(targetclass = ebookinfo.class,
                columns = {
                        @columnresult(name = "book_id", type = long.class),
                        @columnresult(name = "book_name", type = string.class),
                        @columnresult(name = "file_type", type = string.class)
                }))
@namednativequery(name = "listexpressebooks",
        query = "select book_id, book_name, file_type from ebook order by update_date desc",
        resultsetmapping = "ebookinfo")
@entity
@table(name = "ebook")
public class ebook {

    private long bookid;

    private integer authorid;
    private string authorname;
    private integer categoryid;
    private string bookname;
    private string subtitle;
    private string tags;
    private string isbn;
    private string edition;
    private byte booktype;
    private integer star;
    private integer downloadcount;
    private byte status;
    private string filetype;
    private string outline;
    private string introduction;
    private string preface;
    private string cover;
    private float price;
    private string publisher;
    private string bgcolor;
    private string forecolor;
    private string titlecolor;
    private string coverbackgroundid;
    private string coverpictureid;
    private integer covertemplateid;
    private string coverpicturemode;
    private integer pagemode;
    private timestamp requestdate;
    private timestamp publishdate;
    private timestamp updatedate;

定义一个新的dto对象

字段和查询的字段对应,需要提供构造函数:

@data
public class ebookinfo {
    private long bookid;
    private string bookname;    
    private string filetype;

    public ebookinfo(long bookid, string bookname, string filetype) {
        this.bookid = bookid;
        this.bookname = bookname;
        this.filetype = filetype;
    }

}

repository中定义查询接口

    @query(name = "listexpressebooks", nativequery = true)
    public list<ebookinfo> listexpressebooks();

其它方案

查询中构造新对象

public list<blog> selectbyyearmonth(string year, string month, int status) {
    string sql = string.format("select new blog(blog.id, blog.title, blog.abs, blog.createtime) from blog blog where blog.status = %d and year(createtime) = %s and month(createtime) = %s order by blog.createtime desc", status, year, month);

    //query query = this.em.createnativequery(sql, "expressedresult");
    query query = this.em.createquery(sql);
    list results = query.getresultlist();

    return results;
}

上述方法是之前我项目中代码库里的写法,blog需要提供相应的构造函数。

自己写convertor

repository 返回 tuple 对象,自己写代码手动转换为指定对象,repository层使用native查询。

这里要借助辅助类:

class nativeresultprocessutils {

        /**
         * tuple转实体对象
         * @param source tuple对象
         * @param targetclass 目标实体class
         * @param <t> 目标实体类型
         * @return 目标实体
         */
        public static <t> t processresult(tuple source,class<t> targetclass) {
            object instantiate = beanutils.instantiate(targetclass);
            converttupletobean(source,instantiate,null);
            return (t) instantiate;
        }

        /**
         *
         * tuple转实体对象
         * @param source tuple对象
         * @param targetclass 目标实体class
         * @param <t> 目标实体类型
         * @param ignoreproperties 要忽略的属性
         * @return 目标实体
         */
        public static <t> t processresult(tuple source,class<t> targetclass,string... ignoreproperties) {
            object instantiate = beanutils.instantiate(targetclass);
            converttupletobean(source,instantiate,ignoreproperties);
            return (t) instantiate;
        }

        /**
         * 把tuple中属性名相同的值复制到实体中
         * @param source tuple对象
         * @param target 目标对象实例
         */
        public static void converttupletobean(tuple source,object target){
            converttupletobean(source,target,null);
        }

        /**
         * 把tuple中属性名相同的值复制到实体中
         * @param source tuple对象
         * @param target 目标对象实例
         * @param ignoreproperties 要忽略的属性
         */
        public static void converttupletobean(tuple source,object target, string... ignoreproperties){
            //目标class
            class<?> actualeditable = target.getclass();
            //获取目标类的属性信息
            propertydescriptor[] targetpds = beanutils.getpropertydescriptors(actualeditable);
            //忽略列表
            list<string> ignorelist = (ignoreproperties != null ? arrays.aslist(ignoreproperties) : null);

            //遍历属性节点信息
            for (propertydescriptor targetpd : targetpds) {
                //获取set方法
                method writemethod = targetpd.getwritemethod();
                //判断字段是否可以set
                if (writemethod != null && (ignorelist == null || !ignorelist.contains(targetpd.getname()))) {
                    //获取source节点对应的属性
                    string propertyname = targetpd.getname();
                    object value = source.get(propertyname);
                    if(value!=null && classutils.isassignable(writemethod.getparametertypes()[0], value.getclass())) {
                        try {
                            //判断target属性是否private
                            if (!modifier.ispublic(writemethod.getdeclaringclass().getmodifiers())) {
                                writemethod.setaccessible(true);
                            }
                            //写入target
                            writemethod.invoke(target, value);
                        }
                        catch (throwable ex) {
                            throw new fatalbeanexception(
                                "could not copy property '" + targetpd.getname() + "' from source to target", ex);
                        }
                    }
                }
            }
        }

    }

使用entitymanager的transformers.aliastobean

未验证,spring data jpa未必支持

使用entitymanager的transforms.alias_to_entity_map

未验证

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com