Java 加入JPA:为了获得与JDBC相同的结果,我应该编写哪些查询?
我是JPA新手,我试图将我在JDBC中使用的方法转换为JPA作为练习。 这应该计算我数据库中所有恒星的所有质量,并更新相对质量列。为了计算质量,我需要一颗恒星的温度和它在350微米波段的通量值。问题是这些数据保存在数据库的不同表中,因此我必须使用联接 JDBC方法Java 加入JPA:为了获得与JDBC相同的结果,我应该编写哪些查询?,java,postgresql,jpa,jdbc,Java,Postgresql,Jpa,Jdbc,我是JPA新手,我试图将我在JDBC中使用的方法转换为JPA作为练习。 这应该计算我数据库中所有恒星的所有质量,并更新相对质量列。为了计算质量,我需要一颗恒星的温度和它在350微米波段的通量值。问题是这些数据保存在数据库的不同表中,因此我必须使用联接 JDBC方法 public void updateAllMasses() { String selectQuery = "SELECT s.starid, s.temperature, f.value" + " FR
public void updateAllMasses() {
String selectQuery = "SELECT s.starid, s.temperature, f.value" +
" FROM star s JOIN flux f " +
"ON s.starid = f.source " +
"WHERE f.band = 350.00 AND f.value != 0";
try {
ResultSet resultSet = databaseUtilJDBC.dbExecuteQuery(selectQuery);
while (resultSet.next()) {
String starId = resultSet.getString("starid");
Double flux350 = resultSet.getDouble("value");
Double temp = resultSet.getDouble("temperature");
if (temp != 0) {
String updateQuery = "UPDATE star " +
"SET mass = 0.053 * " + flux350 + " * (100) * (EXP(41.14 / " + temp + " ) - 1) "
+ "WHERE starid = '" + starId + "';";
databaseUtilJDBC.dbExecuteUpdate(updateQuery);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
}
JPA进近尝试
在这里,我需要在Star
对象和Flux
对象之间创建一个JOIN
这是Star
课程的草稿
@Entity
@Table(name = "star")
public class Star implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "starid", nullable = false)
private String starId;
@Column(name = "temperature")
private BigDecimal temperature;
@Column(name = "mass")
private BigDecimal mass;
// With all constructors, getters and setters
}
下面是我用于通量的实体类:
@Entity
@Table(name = "flux")
public class Flux implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId private FluxId fluxId = new FluxId();
@Column(name = "value")
private BigDecimal value;
// With constructors, getters and setters
}
使用其idclass:
@Embeddable
public class FluxId implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name = "source", nullable = false)
private String source;
@Column(name = "band", nullable = false)
private BigDecimal band;
// With constructors, getters and setters
}
以下是我对JPA的最后尝试:
public void updateAllMasses() {
String query = "???"; // Query to get all values I need
List list = databaseUtilJPA.dbExecuteQuery(query);
for (Object aList : list) {
Star star = (Star) aList; // Here I would just get a Star object... while I would need also it's flux value at 350 band!
if (!star.getTemperature().equals(BigDecimal.valueOf(0))) {
query = "UPDATE Star star SET star.mass = 0.053 * flux.value * 100 * (EXP(41.14 / star.temperature) - 1)" +
" WHERE star.starId = '" + star.getStarId() + "'";
databaseUtilJPA.dbExecuteUpdate(query);
}
}
}
我应该编写什么查询?JPA也支持本地JDBC查询 但是如果你有一个
one-to-many
关系,那么你可以在jpa
中使用注解来定义它,或者在你的Star
或者Flux
类上,或者两者都可以
@Entity
public class Star {
@OneToMany
private List<Flux> fluxes = new ArrayList<>();
}
@Entity
public class Flux {
@ManyToOne
private Star star;
}
@实体
公务舱明星{
@独身癖
私有列表流量=新的ArrayList();
}
@实体
公共类流量{
@许多酮
私人明星;
}
因此,您的查询可以:
"select star s from Star join s.fluxes f where f.band = ? and f.value <> ?"
“从星形连接s.fluxes f中选择星形,其中f.band=?和f.value?”
您的模型映射不正确。如果你想使用来自JPA的连接,你必须正确地声明它们。您的FLuxId必须如下所示:
@Embeddable
public class FluxId implements Serializable {
@ManyToOne
@JoinColumn(name="source")
private Star star;
@Column(name = "band", nullable = false)
private BigDecimal band;
// With constructors, getters and setters
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || !(obj.getClass().equals(this.getClass())))
return false;
FluxID otherFluxId = (FluxID)obj;
if (this.getSource() == null
|| otherFluxId.getSource() == null
|| this.getBand() == null
|| otherFluxId.getBand() == null)
return false;
return this.getSource().equals(otherFluxId.getSource()) &&
this.getBand().equals(otherFluxId.getBand());
}
@Override
public int hashCode() {
if (this.getSource() == null && this.getBand() == null) return super.hashCode();
return (this.getSource() != null ? this.getSource().hashCode() : 0 ) ^
(this.getBand() != null ? this.getBand().hashCode() : 0 );
}
然后将Flux类标记为具有单独的IdClass:
@Entity
@IdClass(FluxId.class)
public class Flux {
@Id
private Source source;
@Id
private BigDecimal band;
// With constructors, getters and setters
}
警告:绝对有必要为其实现一个正确的equals()方法,以确保持久化后的对象与自身完全相同,并且如果从数据库中检索,则对象也完全相同
确保它看起来像这样:
@Embeddable
public class FluxId implements Serializable {
@ManyToOne
@JoinColumn(name="source")
private Star star;
@Column(name = "band", nullable = false)
private BigDecimal band;
// With constructors, getters and setters
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || !(obj.getClass().equals(this.getClass())))
return false;
FluxID otherFluxId = (FluxID)obj;
if (this.getSource() == null
|| otherFluxId.getSource() == null
|| this.getBand() == null
|| otherFluxId.getBand() == null)
return false;
return this.getSource().equals(otherFluxId.getSource()) &&
this.getBand().equals(otherFluxId.getBand());
}
@Override
public int hashCode() {
if (this.getSource() == null && this.getBand() == null) return super.hashCode();
return (this.getSource() != null ? this.getSource().hashCode() : 0 ) ^
(this.getBand() != null ? this.getBand().hashCode() : 0 );
}
请注意,此实现存在一个缺陷,即hashCode()在持久化之前与持久化之后不同。我不知道如何避免这种情况,但如果在持久化实体之前将其存储在某个集合中,则必须小心
完成所有这些操作后,查询将变为:
SELECT f.source.id, f.source.temperature, f.value
FROM Flux f
WHERE f.band = 350.00 AND f.value != 0
如果需要该对象,也可以使用该对象:
SELECT f.source
FROM Flux f
WHERE f.band = 350.00 AND f.value != 0
(不能100%确定最后一个的语法。)发布实体的代码。不要使用原始类型。泛型从13年前2004年发布的Java5开始就存在于Java中。是时候赶上进度了。@JBNizet按照您的建议添加了代码:)好的。要使用联接,需要实体之间的关联。你的流量的来源应该是星型的,并用manytone或OneToOne注释(取决于基数)。你错过了JPA的要点,它将数据库映射为实体的互连图:一名员工属于一家公司,该公司有地址,链接到一个城市,包含地区等。感谢你非常有用的回答,我将测试它!我有一个问题:一旦执行查询并获得
列表
,如何访问结果?到目前为止,我一直习惯于只获取我已经拥有的对象,而不是为查询“定制”的对象。(因此,我需要runtlist.get(index)
并将其转换为我需要的类)。[例如,相当于JDBC中的resultSet.getBigDecimal(“columnName”)
]如果在JPQL查询中选择多个表达式,您将获得一个对象数组。如果您不想这样做,只需返回selectdistinct s。我建议编写一个单元测试来处理JPQL查询。我认为没有什么好的UI(但是如果你找到了,请告诉我)