基
我有一个由JPA(EclipseLink)管理的mysql数据库(实体和控制器+持久性单元)。 GUI是基于JavaFX的。
的信息
我看到了这篇文章:
和此示例代码
问题
目前我正在使用 我的适配器 (非真正的适配器模式)将JPAEntity转换为JavaFX Bean
public <T, S> Function<T, S> getRefactor() {
return o -> {
Object rtn = null;
//adapt **o** it to JavaFX bean
return (S) rtn;
};
}
,我认为这不是最佳解决方案。
问题 没有混合模式! 我相信在服务器端使用javafx属性是疯狂的,即使是超级懒惰的实现。
有一个灵活的解决方案可以获得JavaFX Bean的所有好处,例如双向绑定,并保留未更改的JPA实体代码?
EDITED
即。目前我有JPAEntity + JPAController和FXClass,&#34;代表&#34; JPAEntity。
JPAEntity是旧式POJO,包含要写入DB的数据。
FXClass具有javafx属性,包含在FX环境中显示的数据。
所以......我正在使用中间层来传达两者。
提前致谢
答案 0 :(得分:7)
我通常会主张在JPA实体中使用JavaFX属性:我真的没有明显的理由不这样做。
但是,如果您想避免这样做,可以使用JavaBeanPropertyAdapter
s。这些是创建包装常规JavaBean属性的JavaFX可观察属性的适配器。所以如果你有一个bean类
@Entity
public class Person {
private String firstName ;
private String lastName ;
@Id
private Integer id ;
public String getFirstName() {
return firstName ;
}
public void setFirstName(String firstName) {
this.firstName = firstName ;
}
public String getLastName() {
return lastName ;
}
public void setLastName(String lastName) {
this.lastName = lastName ;
}
}
然后你可以做类似
的事情TableColumn<Person, String> firstNameCol = new TableColumn<>("First Name");
firstNameCol.setCellValueFactory(cellData -> {
try {
return JavaBeanStringPropertyBuilder.create()
.bean(cellData.getValue())
.name("firstName")
.build();
} catch (NoSuchMethodException exc) {
throw new RuntimeException(exc);
}
});
这将创建一个在表中使用的JavaFX属性,并单向地将JavaBean属性绑定到它:即,如果更改表中的值,JavaBean将被更新。使用此设置不会发生反向绑定,即更改bean中的值不会更新表中显示的值。
如果您想要双向绑定,您的bean将需要支持属性更改侦听器:
public class Person {
private String firstName ;
private String lastName ;
private PropertyChangeSupport pcs ;
public Person() {
pcs = = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
String oldName = this.firstName ;
this.firstName = firstName;
pcs.firePropertyChange("firstName", oldName, this.firstName);
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
String oldName = this.lastName ;
this.lastName = lastName;
pcs.firePropertyChange("lastName", oldName, this.lastName);
}
}
现在对bean的更改将传播到表使用的JavaFX属性,反之亦然。
答案 1 :(得分:2)
另一种可能的嵌入式内置AFAIK解决方案。
...允许从另一个类使用现有类的接口 接口。它通常用于使现有的类与其他类一起工作 没有修改他们的源代码。
此示例仅供参考,并非确认的解决方案,但需要编写结构良好且灵活的代码以进行更改。 所以......
示例:强>
如果我们有像
这样的JPAEntity@Entity
@Table(name="EntityClass", uniqueConstraints = {
@UniqueConstraint(columnNames = {"ID"})})
@XmlRootElement
@NamedQueries({
@NamedQuery(name = "EntityClass.findAll", query = "SELECT a FROM EntityClass a"),
@NamedQuery(name = "EntityClass.findById", query = "SELECT a FROM EntityClass a WHERE a.id = :id"),
@NamedQuery(name = "EntityClass.findByYear", query = "SELECT a FROM EntityClass a WHERE a.year = :year")})
public class EntityClass implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(nullable = false)
private Integer id;
@Basic(optional = false)
@Column(nullable = false, length = 4)
private String year;
//...and others
private static final long serialVersionUID = 1L;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "fKYear")
private Collection<Some1> some1Collection;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "fKYear")
private Collection<Some2> some2Collection;
public EntityClass() {
}
public EntityClass(Integer id) {
this.id = id;
}
public EntityClass(Integer id, String year) {
this.id = id;
this.year = year;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
@XmlTransient
public Collection<Some1> getSome1Collection() {
return some1Collection;
}
public void setSome1Collection(Collection<Some1> some1Collection) {
this.some1Collection = some1Collection;
}
@XmlTransient
public Collection<Some2> getSome2Collection() {
return some2Collection;
}
public void setSome2Collection(Collection<Some2> some2Collection) {
this.some2Collection = some2Collection;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof EntityClass)) {
return false;
}
EntityClass other = (EntityClass) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return this.year;
}
}
我们创建了一个像这样的接口
public interface IFXEntityClass{
void setYear(String year);
String getYear();
//...
void setSome1Collection(Collection<Some1> some1);
Collection<Some1> getSome1Collection();
//...
}
我们可以创建像
这样的FXClasspublic class FXEntityClass implements IFXEntityClass{
private final StringProperty yearProperty=new SimpleStringProperty();
public StringProperty getYearProperty(){ return this.yearProperty;}
public void setYear(String year){ this.year.set(year); }
public String getYear(){ return this.year.get(); }
//...
void setSome1Collection(Collection<Some1> some1)( //do something)
Collection<Some1> getSome1Collection(){ return null;}
//...
}
现在我们拥有了所需的一切。让我们创建适配器。
public class EntityClassToFXEntityClassAdaptor implements IFXEntityClass{
private EntityClass entity;
private final StringProperty yearProperty=new SimpleStringProperty();
public EntityClassToFXEntityClassAdaptor(EntityClass e){
this.entity=e;
//adapt it as you want
this.yearProperty.set(e.getYear());
//...
}
public StringProperty getYearProperty(){ return this.yearProperty;}
public void setYear(String year){ this.year.set(year); }
public String getYear(){ return this.year.get(); }
//...
void setSome1Collection(Collection<Some1> some1)( //do something)
Collection<Some1> getSome1Collection(){ return null;}
//...
}
最后我们可以使用它
EntityClass ec=something; //get an instance of JPAEntity
EntityClassToFXEntityClassAdaptor adaptor=new EntityClassToFXEntityClassAdaptor(ec);
adaptor.getYearProperty();
在
中找到更清晰的如何应用此模式的示例import java.awt.*;
public class CheckboxAdapter extends Checkbox{
public CheckboxAdapter(String n){
super(n);
}
public boolean isSelected(){
return getState();
}
//... continue
}