JavaFX:基于属性的实体与基于属性的包装器
我使用的是包含JavaFX属性的模型实体,它允许我更改单个位置上的值,将它们绑定到UI,并在模型实体数组中添加具有额外条件的更改侦听器(唯一值等) 我必须将模型存储在数据库中,因此问题如下: 我是否应该将模型实体转换为JPA实体(使用AccessType.PROPERTY设置值),而不需要将所有值(或所有时间)都设置为属性,或者使用基于属性的包装器(面向)创建经典的基于值的实体类来访问它JavaFX:基于属性的实体与基于属性的包装器,java,jpa,javafx,properties,wrapper,Java,Jpa,Javafx,Properties,Wrapper,我使用的是包含JavaFX属性的模型实体,它允许我更改单个位置上的值,将它们绑定到UI,并在模型实体数组中添加具有额外条件的更改侦听器(唯一值等) 我必须将模型存储在数据库中,因此问题如下: 我是否应该将模型实体转换为JPA实体(使用AccessType.PROPERTY设置值),而不需要将所有值(或所有时间)都设置为属性,或者使用基于属性的包装器(面向)创建经典的基于值的实体类来访问它 注意:一些可绑定属性根本不需要持久化。您是否应该使用特定的技术是基于意见的,因此我不会在这里回答您的确切问题
注意:一些可绑定属性根本不需要持久化。您是否应该使用特定的技术是基于意见的,因此我不会在这里回答您的确切问题。我将只提供一些正反两方面的选择 直接在JPA注释实体类中使用JavaFX属性的优点是,可以保持设计的简单性,每个实体只有一个类,而不是实体注释类周围的包装类 直接在JPA实体类中使用JavaFX属性的缺点是:
@Entity
@Access(AccessType.PROPERTY)
public class Person {
private IntegerProperty age ;
private int _age ;
private StringProperty name ;
private String _name ;
private int id ;
@Id
public int getId() {
return id ;
}
public void setId(int id) {
this.id = id ;
}
public IntegerProperty ageProperty() {
if (age == null) {
age = new SimpleIntegerProperty(_age);
}
return age ;
}
public int getAge() {
if (age == null) {
return _age ;
} else {
return age.get();
}
}
public void setAge(int age) {
if (this.age == null) {
_age = age ;
} else {
this.age.set(age);
}
}
public StringProperty nameProperty() {
if (name == null) {
name = new SimpleStringProperty(_name);
}
return name ;
}
public String getName() {
if (name == null) {
return _name ;
} else {
return name.get();
}
}
public void setName(String name) {
if (this.name == null) {
_name = name ;
} else {
this.name.set(name);
}
}
}
这基本上避免了(几乎)由于在非JavaFX环境中使用此类而产生的任何性能开销,因为除非通过xxxProperty()
方法显式请求,否则不会实例化属性。请注意,调用这些方法是注册侦听器的唯一方法,因此如果已注册侦听器,则代码保证在随后调用setXxx(…)
时通知这些侦听器。这里的代价是一些代码冗长和一些冗余空检查的非常小的代价(JVM可能会为此进行优化)
这种技术显然无法解决对javafxapi的依赖性问题
另一个可能的选择是将普通JavaBean与属性更改侦听器一起使用:
@Entity
public class Person {
@Id
private int id ;
private int age ;
private String name ;
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public int getAge() {
return age ;
}
public void setAge(int age) {
int oldAge = age ;
this.age = age ;
pcs.firePropertyChange("age", oldAge, age);
}
public String getName() {
return name ;
}
public void setName(String name) {
String oldName = name ;
this.name = name ;
pcs.firePropertyChange("name", oldName, name);
}
// ...
}
现在,在JavaFX客户端中,您可以执行以下操作:
TableView<Person> contactTable = new TableView<>();
TableColumn<Person, String> nameCol = new TableView<>("Name");
nameCol.setCellValueFactory(cellData -> {
try {
return JavaBeanStringPropertyBuilder.create()
.bean(cellData.getValue())
.name("name")
.build();
} catch (Exception exc) {
return new RuntimeException(exc);
}
});
具有明显的实现
@Entity
public class PersonEntity implements Person {
private int age ;
private String name ;
@Id
private int id ;
// get/set methods omitted...
}
及
现在,在JavaFX客户机中,您可以拥有一个JSON引擎,该引擎将JSON从
PersonFX
实例中[反]序列化,在服务器上,您可以拥有一个JSON引擎,该引擎将相同的JSON数据从PersonEntity
实例中[反]序列化。由于JSON引擎将只通过调用get/set方法来工作,因此从其角度来看,对象本质上具有相同的形式。自从我开始使用JavaFX以来,我还没有处理过与XML数据之间的序列化,因此我不确定同样的方法是否适用于XML数据,但我认为您也可以做到这一点。通过在实现类中定义readObject
和writeObject
方法,您甚至可以使用Java序列化流实现这一点,这些方法需要相同形式的数据(或使用序列化代理)。您能澄清您的问题吗?您正在询问使用JavaFX属性实现JPA实体是否是一个好的设计,当该实体有时将在JavaFX上下文中使用(需要可观察的属性),有时在不同的上下文中使用(不需要属性中的任何功能)事实上,这正是我要问的。我越想它,我总是回到某种包装上(顺便说一句,谢谢:-)。应用程序不需要处理来自多个源的数据(序列化)。实体将主要代表统计结果(在大多数情况下)。但是,我必须创建一个手动工具,用于测量和插入这些数据。这可能会改变特性,可能会创建新的(更自动化的)工具,或者引入不同的测量方法。包装器可以帮助我独立地调整每个案例的外观。
@Entity
public class PersonEntity implements Person {
private int age ;
private String name ;
@Id
private int id ;
// get/set methods omitted...
}
public class PersonFX implements Person {
private final StringProperty name = new SimpleStringProperty() ;
private final IntegerProperty age = new SimpleIntegerProperty() ;
public StringProperty nameProperty() {
return name ;
}
@Override
public final String getName() {
return nameProperty().get();
}
@Override
public final void setName(String name) {
nameProperty().set(name);
}
// similarly for age...
}