3

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

例如:

@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_nameandT_PERSON作为输入,我想在其中设置一些值。

我发现这个这个使用列名来获取字段名,我可以用它Reflection来获取setter方法,但是有没有反射的替代方法?

4

5 回答 5

4

我认为你最好的选择是只使用反射。Hibernate 在内部也使用反射来读取通过注释完成的所有映射。如果你想尝试hibernate内部类然后看看Hibernate的SessionFactory实现类(org.hibernate.impl.SessionFactoryImpl),它为每个实体保存了包含类元数据(org.hibernate.metadata.ClassMetadata)的映射。您必须已经在代码中引用了单例 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

此外,如果您有用于初始化休眠的配置对象的引用,您可以查询您感兴趣的表

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
于 2013-10-25T20:23:40.797 回答
0

虽然我通常同意这些评论 - 我会使用 JDBCTemplate 或类似的东西来完成你所追求的,你可能会查看一个字段上的 @Transient 注释,或者可能只是写一些类似的东西:

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

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

我重申,我不认为这真的是管理这个问题的理想方式,但如果你绝对嫁给了休眠,这将是做你想做的事情的一种方式(我认为)

于 2013-10-21T00:44:56.347 回答
0

您可以使用以下方法运行常见的 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 注入的影响。

于 2013-10-25T13:47:51.217 回答
0

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

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

像这样的东西:

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

}

希望这可以帮助。

于 2013-10-27T08:40:52.147 回答
0

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

将规则应用于用户输入的表列名并识别实体类属性并调用 setter 方法。

如果无法控制实体类属性名称,那么使用反射是最好的方法。

于 2013-10-24T09:20:38.867 回答