Hibernate:按列名设置字段

时间:2013-09-08 14:56:52

标签: java hibernate jpa

有没有办法在实体中设置一些只包含字段列名称信息的字段?

例如:

@Entity
@Table(name = "T_PERSON")
public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "p_id")
    private int id;

    @Column(name = "p_name")
    private String name;

    // getters and setters for id and name
}

所以我将p_nameT_PERSON作为输入,我想在其中设置一些值。

我找到thisthis来使用列名获取字段名称,我可以使用Reflection来获取setter方法,但是有没有替代反射?

5 个答案:

答案 0 :(得分:3)

我认为你最好的选择只是使用反射。 Hibernate内部也使用反射来读取通过注释完成的所有映射。如果你想试试hibernate内部类,那么看一下Hibernate的SessionFactory实现类(org.hibernate.impl.SessionFactoryImpl),它为每个实体保存包含类元数据(org.hibernate.metadata.ClassMetadata)的map。您必须在代码中引用单例SessionFactory。

您可以使用

获取ClassMeta数据
public ClassMetadata getClassMetadata(Class persistentClass) throws HibernateException 

ClassMetaData中的方法很少,这可能是你感兴趣的。例如,

public void setPropertyValue(Object object, String propertyName, Object value, EntityMode entityMode) throws HibernateException;

EntityMode可以指定为EntityMode.POJO

此外,如果你有一个用于初始化hibernate的Configuration对象的引用,你可以查询你感兴趣的表

public Table getTable(String schema, String catalog, String name) {
            String key = Table.qualify(catalog, schema, name);
            return tables.get(key);
        }

并且有方法来获取物理或逻辑列名称

public String getPhysicalColumnName(String logicalName, Table table) throws MappingException

public String getLogicalColumnName(String physicalName, Table table) throws MappingException

答案 1 :(得分:1)

虽然我普遍同意这些评论 - 我会使用JDBCTemplate或其他类似的东西来完成你所追求的东西,你可能会研究一个字段上的@Transient注释,或者可能只是写下这样的东西:

public void setFieldForColumnName(String columnName, Object value){
    Switch(columnName){
        case("columnA"):
            setColumnA(value);
            break;
        default:
            // ....
            break;
    }
}

当然,这依赖于一个字符串开关 - 如果你没有能够打开字符串,你必须转换为if / then。

我重申,我认为这不是理想的管理方式,但如果你绝对与hibernate结婚,这将是你想做的事情的一种方式(我想)

答案 2 :(得分:1)

如果您可以控制Entity类属性名称创建,则根据表列名称创建java属性名称(例如,应用规则:规则1 - 列p_name为pName)。

在用户输入表列名称上应用规则并标识实体类属性并调用setter方法。

如果没有对Entity类属性名称的控制,那么使用反射是最好的方法。

答案 3 :(得分:1)

您可以使用以下方法运行常见的SQL更新查询:

public int updateSomeParameter(String tableName, String idColumnName, int id,
                               String parameterColumnName, Object newParameterValue) {
    String sql = "UPDATE " + tableName + " SET " + parameterColumnName
                 + " = :new_value WHERE " + idColumnName + " = :id";
    SQLQuery query = session.createSQLQuery(sql);
    query.setInteger("id", id);
    query.setParameter("new_value", newParameterValue);
    return query.executeUpdate();
}

int updateCout = updateSomeParameter("T_PERSON", "p_id", 50, "p_name", "Some New Name");

但这种方式是 高度推荐的 ,特别是如果表名和列名来自用户输入,因为它很容易引起SQL注入。

答案 4 :(得分:1)

由于在编译时不知道要调用的方法,根据我的理解,反射是唯一的方法。

如果您试图避免在调用代码中使用反射,则可以编写一个包装器方法,在内部使用反射来进行设置,然后在调用方法中使用该方法。

这样的事情:

public static <T> Map<String, java.lang.reflect.Method> obtainMapOfColumnNamesAndSetters(Class<T> classType) {
     Map<String, java.lang.reflect.Method> result = null;

     /*
      * Use reflection to iterate over all fields and 
      * identify ones with annotation and build a map of database column names and fields 
      * and use the field names to obtain the setter method references and save it in a map and return it as result.
      * 
      * The result map's key is the column name and the value is the method to be set.
      * 
      * Note: Ideally, this map needs to be build only once per class.
      */
    return result;
}

public static boolean genericHibernatePropertySetter(Object beanObject, Object parameterObject, String annotationValue, 
        Map<String, java.lang.reflect.Method> columnAndMethodMap) 
{
    boolean result = false;

    /*
     * Use this method to hide the reflection from invoking classes.
     *        
     * Fetch the corresponding 'java.lang.reflect.Method' instance from the map. 
     * Use the method instance to set the parameter on the bean object.
     * 
     */

    return result; // set to true in the implementation

}

希望这有帮助。