2013-01-21 62 views
0

我需要得到一个Field(或一个字段列表),而不知道它的名字。Java:不知道名称的访问字段。 (“保存参考”)

即:自定义的EntityManager我希望能够做到的方法调用是这样的:

cem.getEntities(MyEntity.class, ParamMap)其中ParamMap应该是类型Map<Field, Object>的。

可以在瞬间做的是这样的:

Map<Field, Object> params = new HashMap<Field, Object>(); 
params.put(MyEntity.class.getDeclaredField("someFieldName"), 20); 
List<MyEntity> entitysWithSomeFieldNameEquals20 = cem.getEntities(MyEntity.class, params); 

我试着避免querys的使用,因为它应该摆在首位的工作“一般”,而且是独立的来自Strings。 (他们很容易出错)。因此,实体管理器使用反射来确定表格和列名称,他需要使用。

不过,我仍然需要使用

MyEntity.class.getDeclaredField("someFieldName") 

这将简单的移动容易出错的字符串“走出去”的实体管理器的...

我正在努力实现将是这样的:

MyEntity.class.getDeclaredField(MyEntity.class.fields.someFieldName.toString()) 

所以,无论什么实际的场而得名,它可以在保存方式和重构引用将重构所有的现场访问调用了。

我不确定这是否可能。我可以为所有实体使用(封装)枚举,但我希望,这是更通用的方法来实现这一点。


编辑:

一个很好的解决方案似乎是常量的使用:

public class MyEntity{ 
    private static string SOME_FIELD = "some_field_name_in_database"; 

    @Column(name = SOME_FIELD); 
    private String someField; 

} 

... 
Map<String, Object> params = new HashMap<String, Object>(); 
params.put(MyEntity.SOME_FIELD, matchValue); 
List<MyEntity> result = eem.getEntities(MyEntity.class, params); 

这至少减少了串正好一个位置,它可以维持到使用并在不影响其他文件的情况下更改但是我仍然在寻找无常数的解决方案,所以contants 不需要与可用字段 :-)

+1

你想游泳但没有变湿?使用字符串键的属性集合有什么问题?只要你让它们成为一个枚举或类似的东西,它们就不再是“通用的”了。所以我认为你的要求相互矛盾。 – Fildor

+0

但你确实知道该字段的名称(这里是“someFieldName”)?否则,你想如何用不知道字段名称的值填充ParamMap?我想这里的问题是你不想使用字符串? – proskor

+0

是的,当然我知道字段名称。但我不想将它们(硬编码)放入字符串中。所以问题是,如果我可以以某种方式引用它们,比如使用枚举,而不为每个实体(需要维护)创建一个枚举。对每个实体使用嵌入式枚举不起作用,因为JPA不允许从枚举中获取列名(column.name需要是一个常量表达式)...不要误解我的意思:更改实体总是会导致要做的工作。但是你不能找到某个字符串的每一个用法,比如你可以引用enums/Constants的用法。 – dognose

回答

0

好的同步,这只是一个想法,这是不容易实现,但它可以工作。

假设myEntity所看起来像这样:

public class MyEntity { 
    private String foo; 
    private String bar; 

    public String getFoo() { return this.foo; } 
    public void setFoo(String foo) { this.foo = foo; } 

    public String getBar() { return this.bar; } 
    public void setBar(String bar) { this.bar = bar; } 

}

并且有一个接口:

public interface Pattern { 
    public Class<?> getEntityClass(); 
    public Map<Field, Object> getFields(); 
} 

并有一个方法,它采用一个类,并且产生一个图形对象,这是给定类别的一个实例:

public class PatternFactory { 
    public <T> T createPattern(Class<T> klass) { 
    // magic happens here 
    } 
} 

对发出的实例的要求是它应该实现Pattern接口,这样方法getFields只返回明确设置的字段。 GetEntityClass应该返回实体类。然后自定义实体管理器可以实现这样的:

public class EntityManager { 
    public <T> Collection<T> getEntities(T pattern) { 
    if (!(pattern instanceof Pattern)) 
     throw new IllegalArgumentException(); 

    Class<?> klass = ((Pattern) pattern).getEntityClass(); 
    Map<Field, Object> fields = ((Pattern) pattern).getFields(); 
    // fetch objects here 
    } 
} 

然后,你可以使用这样的:

PatternFactory pf = // obtain somehow 
EntityManager em = // obtain somehow 
MyEntity pattern = pf.createPattern(MyEntity.class); 
pattern.setFoo("XYZ"); 
pattern.setBar(null); 
Collection<MyEntity> result = em.getEntities(pattern); 

在这种情况下pattern.getFields会返回地图的两个项目。

当然,这里的难点在于createPattern方法的实现,在这个方法中,您将不得不在运行时发出字节码。但是,这是可能的,可以完成的。

相关问题