将查询结果映射到 Java 中的 POJO 构造函数

Map query results to POJO constructor in Java

我有一组 SQL 查询和一个带有构造函数的相应 POJO 对象。

例如。

Student student = new Student(rs.getString("FNAME"), rs.getString("LNAME"), rs.getString("GRADE"));

目前我正在手动将结果集中的列映射到一个字段。我想让这个通用化,这样我就可以做一些像 new Student(rs.getRow()) 这样的事情,然后我可以通过某种配置文件来映射它。 select 查询中可能有 N 个字段,并且顺序不一定与构造函数中定义的顺序匹配。

我想控制 SQL,因为它可能有很多连接,所以我不确定 ORM 是否可以在这里工作。我非常想要可以将结果集列映射到字段的东西。

我想在我的 Student class 中添加注释以进行映射

如果您的查询结果是像 Student 这样的域对象(不管 FROM 语句中有多少个连接),那么 ORM 就可以正常工作,也许它是一个很好的解决方案。如果您要提取一些复杂的数据结构,那么您可以查看一些 Spring 功能,例如 RowMapper。

public class StudentRowMapper implements RowMapper<YourStudentPojo> {


@Override
public YourStudentPojo mapRow(final ResultSet rs, final int arg1) throws SQLException {

    final YourStudentPojo item = new YourStudentPojo();
    item.setFName(rs.getString("FNAME"));

    return item;

}

类似于这个FName,你可以在你的pojo中设置其他值。不需要构造函数。只是如果你在Pojo中进行了修改,则必须在该方法中进行相应的修改。

您可以使用 GSON 序列化对象映射。

refer

它并不完美,但看看这个:

public class Student {
    private String name;
    private Integer age;
    //etc.

    public Student() {
        //default constructor
    }

    public Student(final ResultSet rs) throws Exception {
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();

        for (int i = 1; i < columnCount + 1; i++ ) {
          String name = rsmd.getColumnName(i);

          if (Student.getField(name)) {
              Student.getField(name).set(rs.getString(name));               
          }
        }       
    }
}

您还应该将字段映射到列类型,例如我只使用了 getString。

这看起来确实像是使用 JPA 或类似 ORM 技术的地方的教科书示例。

但是,如果您只想使用注释来执行此操作,则可以创建自己的注释 - http://www.mkyong.com/java/java-custom-annotations-example/ 是一个很好的教程。

您将创建自己的 @DatabaseField 注释,您将使用该注释来注释对象的字段,并指定相应的数据库字段。然后,在构造函数中,获取 class (Class klass = this.getClass()),在其上获取声明的字段 (klass.getDeclaredFields()),然后对于其中的每一个,请查看声明的注释 (field.getDeclaredAnnotations())。对于其中的每一个,如果它们是您的自定义数据库字段注释,请记下映射。完成所有字段后,您将获得字段到数据库列的映射,然后您可以继续使用反射进行设置(您拥有的 Field 对象上有一个 set 方法,您将使用 "this"(正在构造的对象)和你从结果集中得到的值。

这可能是一个有趣的练习,但我仍然认为您最好使用 JPA 或像 SimpleORM 这样的更轻量级的 ORM。

您可以使用 java 反射。 例如,我们将您的 sql 查询是这样的。

SELECT FirstName 'FNAME', LastName 'LNAME', Grade 'GRADE' FROM Employee

所以你会得到如下输出

FNAME        LNAME           GRADE

John          Dan              A+

然后在你的 java 代码中你需要反射来实现其余的

假设你的学生class是这样的

public class Student {

private String LNAME;
private String FNAME;
private String GRADE;

public String getLNAME() {
    return LNAME;
}
public void setLNAME(String lNAME) {
    LNAME = lNAME;
}
public String getFNAME() {
    return FNAME;
}
public void setFNAME(String fNAME) {
    FNAME = fNAME;
}
public String getGRADE() {
    return GRADE;
}
public void setGRADE(String gRADE) {
    GRADE = gRADE;
} }

并且您可以使用以下代码在 Student class 中设置相应的值。

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;


public class Main {


    public static void main(String[] args) {
        try {
            //configuring the columns in the sql statement and class
            String[] ColumnArray = new String[]{"LNAME","FNAME","GRADE"}; 

            // making a hashmap to emulate the result set of sql
            HashMap<String, String> rs = new HashMap<String, String>();
            rs.put("FNAME", "John");
            rs.put("LNAME", "Dan");
            rs.put("GRADE", "A+");

            //reflection of the 
            Class cls = Class.forName("Student");
            Object c = cls.newInstance();
            Method[] mtd = cls.getMethods();
            for (String column : ColumnArray) {
                Method method = cls.getMethod("set"+column, String.class);
                    method.invoke(c, new Object[]{rs.get(column)});
            }
        //casting the class to employee
        Student student = (Student) c;

        //Printing the output
        System.out.println(student.getFNAME());
        System.out.println(student.getLNAME());
        System.out.println(student.getGRADE());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (SecurityException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}}

如果您遇到任何问题,请告诉我。很高兴能帮到你。

在此处查看 HIbernate SQLQuery addScalar() 示例 http://www.journaldev.com/3422/hibernate-native-sql-example-addscalar-addentity-addjoin-parameter-example

这将准确地将总结果集作为 POJO 对象。您稍后可以遍历它以获取数据。

如果这对你有帮助,请告诉我。

假设您的学生table如下。

__________________________
|STUDENT_ID | AGE | NAME |
--------------------------
|           |     |      |
|           |     |      | 
--------------------------

您必须控制 SQL 查询。它的 return 列必须根据 POJO class 的变量名进行重命名。所以 SQL 查询如下所示。

SELECT AGE AS age, NAME AS name from STUDENT;

最后,POJOclass的构造函数如下。它将遍历 class 中的所有私有变量,并检查这些列在 ResultSet 中是否可用。

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.ResultSet;

public class Student
{
    private int age;
    private String name;

    public int getAge()
    {
        return age;
    }

    public void setAge( int age )
    {
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

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

    public static void main( String[] args )
    {
        new Student( null );
    }

    public Student( ResultSet rs )
    {
        Field[] allFields = this.getClass().getDeclaredFields();
        for ( Field field : allFields )
        {
            if ( Modifier.isPrivate( field.getModifiers() ) )
            {
                String fieldName = field.getName();
                String methodName = "set" + fieldName.substring( 0, 1 ).toUpperCase() + fieldName.substring( 1 );

                try
                {
                    Method setterMethod = this.getClass().getMethod( methodName, field.getType() );
                    setterMethod.invoke( this, rs.getObject( fieldName ) );
                }
                catch ( Exception e )
                {
                    e.printStackTrace();
                }

            }
        }
    }
}