2 回答

TA貢獻(xiàn)2037條經(jīng)驗(yàn) 獲得超6個(gè)贊
最簡單的方法是讓您的所有JPA實(shí)體都從這樣的基本實(shí)體擴(kuò)展:
public abstract class BaseEntity<T extends Number> implements Serializable {
private static final long serialVersionUID = 1L;
public abstract T getId();
public abstract void setId(T id);
@Override
public int hashCode() {
return (getId() != null)
? (getClass().getSimpleName().hashCode() + getId().hashCode())
: super.hashCode();
}
@Override
public boolean equals(Object other) {
return (other != null && getId() != null
&& other.getClass().isAssignableFrom(getClass())
&& getClass().isAssignableFrom(other.getClass()))
? getId().equals(((BaseEntity<?>) other).getId())
: (other == this);
}
@Override
public String toString() {
return String.format("%s[id=%d]", getClass().getSimpleName(), getId());
}
}
請(qǐng)注意,擁有一個(gè)適當(dāng)?shù)膃quals()(和hashCode())很重要,否則您將面臨“ 驗(yàn)證錯(cuò)誤:值無效”。該Class#isAssignableFrom()測(cè)試是避免如Hibernate基于代理失敗的測(cè)試,而不需要回落到休眠特定Hibernate#getClass(Object)的輔助方法。
并擁有這樣的基礎(chǔ)服務(wù)(是的,我忽略了您使用Spring的事實(shí);這只是給出基本思想):
@Stateless
public class BaseService {
@PersistenceContext
private EntityManager em;
public BaseEntity<? extends Number> find(Class<BaseEntity<? extends Number>> type, Number id) {
return em.find(type, id);
}
}
并實(shí)現(xiàn)轉(zhuǎn)換器如下:
@ManagedBean
@ApplicationScoped
@SuppressWarnings({ "rawtypes", "unchecked" }) // We don't care about BaseEntity's actual type here.
public class BaseEntityConverter implements Converter {
@EJB
private BaseService baseService;
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) {
return "";
}
if (modelValue instanceof BaseEntity) {
Number id = ((BaseEntity) modelValue).getId();
return (id != null) ? id.toString() : null;
} else {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
}
}
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
try {
Class<?> type = component.getValueExpression("value").getType(context.getELContext());
return baseService.find((Class<BaseEntity<? extends Number>>) type, Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid ID of BaseEntity", submittedValue)), e);
}
}
}
請(qǐng)注意,它被注冊(cè)為@ManagedBean而不是@FacesConverter。這個(gè)技巧可以讓您通過例如在轉(zhuǎn)換器中注入服務(wù)@EJB。另請(qǐng)參見如何在@FacesConverter中注入@ EJB,@ PersistenceContext,@ Inject,@ Autowired等?因此,您需要引用converter="#{baseEntityConverter}"而不是converter="baseEntityConverter"。
如果您碰巧將此類轉(zhuǎn)換器更多地用于UISelectOne/ UISelectMany組件(<h:selectOneMenu>和朋友),您可能會(huì)發(fā)現(xiàn)OmniFaces SelectItemsConverter更加有用。它基于可用的值進(jìn)行轉(zhuǎn)換,<f:selectItems>而不是每次都進(jìn)行(可能很昂貴)DB調(diào)用。
添加回答
舉報(bào)