Java 如何处理JPA多对一关系?
我正在设计一个用于收集天气数据的应用程序。我有两个POJO对象“位置”和“记录”。位置包含有关纬度和经度以及当前天气状况的信息,记录包含特定位置随时间变化的所有天气信息,因此与位置存在多对一关系。我的课程定义如下: Location.javaJava 如何处理JPA多对一关系?,java,jpa,ejb-3.1,many-to-one,Java,Jpa,Ejb 3.1,Many To One,我正在设计一个用于收集天气数据的应用程序。我有两个POJO对象“位置”和“记录”。位置包含有关纬度和经度以及当前天气状况的信息,记录包含特定位置随时间变化的所有天气信息,因此与位置存在多对一关系。我的课程定义如下: Location.java @Entity @Table(name = "location") @NamedQueries( { @NamedQuery(name = "findLocations", query = "SELECT e FROM Location e ORDER
@Entity
@Table(name = "location")
@NamedQueries( {
@NamedQuery(name = "findLocations", query = "SELECT e FROM Location e ORDER BY e.longitude, e.latitude"),
@NamedQuery(name = "findLocationByLatLong", query = "SELECT e from Location e WHERE e.latitude = :latitude AND e.longitude = :longitude"),
@NamedQuery(name = "findLocationById", query = "SELECT e from Location e WHERE e.id = :id"),
@NamedQuery(name = "deleteLocationById", query= "DELETE Location e WHERE e.id = :id"),
@NamedQuery(name = "updateLocation", query = "UPDATE Location e SET e.lastModifiedDate = :lastModifiedDate WHERE e.id = :id")})
public class Location implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long id;
@Column(name="latitude", nullable=false)
protected String latitude;
@Column(name="longitude", nullable=false)
protected String longitude;
@Column(name="lastModifiedDate")
@Temporal(TemporalType.TIMESTAMP)
private Date lastModifiedDate;
@Column(name="windDirection")
private float windDirection;
@Column(name="windSpeed")
private float windSpeed;
@Column(name="temperature")
private float temperature;
}
和Record.java
@Entity
@Table(name = "weatherdata")
@NamedQueries( {
@NamedQuery(name = "findWeatherRecordById", query = "SELECT e from Record e WHERE e.id = :id"),
@NamedQuery(name = "findWeatherRecords", query = "SELECT e from Record e WHERE e.parent = :parent") })
public class Record implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
protected Long id;
@Column(name="mTime")
@Temporal(TemporalType.TIMESTAMP)
private Date mtime;
@Column(name="windDirection")
private float windDirection;
@Column(name="windSpeed")
private float windSpeed;
@Column(name="temperature")
private float temperature;
@ManyToOne(cascade = { CascadeType.ALL }, targetEntity=Location.class, fetch = FetchType.EAGER)
@JoinColumn(name="locationId")
protected Location parent;
}
我的输入数据的形式如下:
latitude,longitude,date,winddirection,windspeed,temperature
36.9822,-122.0153,20100907000000.00,158,2.68,20.57
38.1838,-120.54,20100907000000.00,248,0,26.68
38.3495,-121.9688,20100907000000.00,149,0.45,33.9
38.41935,-121.36029,20100907000000.00,322,0.9,33.9
37.91617,-122.286,20100907000000.00,224,0,24.46
38.587,-121.3162,20100907000000.00,315,0,34.46
36.8717,-121.6555,20100907000000.00,294,3.13,18.34
现在,每当我得到一条记录,我都想把它插入记录表中。由于我有一个指向Location的外键,我还将添加Location表的locationId。
另一件事,位置表不是预先填充的。所以,每当出现新记录时,我首先将其插入位置表,然后用外键填充记录表。我不想在位置表中重复位置项。位置表还将包含您可以看到的最新温度、风速和风向数据
我使用以下代码来实现这一点:
Location loc = handler.getLocation(line);
//loc.setTemperature(0);
Location dbLoc = null;
try {
Query q = eManager.createNamedQuery("findLocationByLatLong");
q.setParameter("latitude", loc.getLatitude());
q.setParameter("longitude", loc.getLongitude());
dbLoc = (Location) q.getSingleResult();
} catch (Exception e) {
System.out.println("Location not found! Creating new location");
Logger.getLogger("WeatherRecorderBean.class").log(Level.WARNING, e.getMessage());
}
Record r = handler.getRecord(line);
if(dbLoc!=null) {
r.setParent(dbLoc);
dbLoc.setLastModifiedDate(r.getMtime());//I am doing this so as to know what time the weather change entry is about
dbLoc.setWindDirection(r.getWindDirection());
dbLoc.setWindSpeed(r.getWindSpeed());
dbLoc.setTemperature(r.getTemperature());
eManager.merge(r);
}
else {
dbLoc = new Location();
dbLoc.setLatitude(loc.getLatitude());
dbLoc.setLongitude(loc.getLongitude());
//eManager.persist(dbLoc);
r.setParent(dbLoc);
dbLoc.setLastModifiedDate(r.getMtime());
dbLoc.setWindDirection(r.getWindDirection());
dbLoc.setWindSpeed(r.getWindSpeed());
dbLoc.setTemperature(r.getTemperature());
eManager.merge(r);
//eManager.merge(dbLoc);
}
但通过这样做,正在发生的是位置被复制。这意味着我在位置表中有多个相同经纬度但不同温度、风速数据的条目。我想做的是为一个纬度和经度设置一个条目,并用最新数据更新风速、温度和风向字段
请帮忙 您将
所有操作从记录
级联到位置
,因此当您合并新的记录
和它的新父记录
位置
时,无需再次合并临时的位置
(否则您将得到重复的行)
我在下面的代码中添加了一些注释(我并没有修复所有问题,还有更多问题,但建议的更改至少应该删除重复项的创建Location
条目):
已解决:-)
我创建了一个用于保存位置的新函数。
我也有一些同步问题。我在MDBonMessage()函数中有这个函数。因此,在一个onMessage()
完成之前,另一个开始创建重复条目
希望这对将来有帮助 嗨,谢谢你的帮助。我更改了代码(也相应地更新了问题中的上述代码)。但它仍然会给我重复的条目(@Vashishtha我可能遗漏了什么,但至少上面的说法不正确。激活SQL日志记录以查看发生了什么。我不能为您这样做:)@Pascal I启用了SQL日志记录,我看到的只是一系列insert语句:(如果任何列的任何单个值不同,则会将新行相互关联。@Vashishtha哪个部分没有按预期工作?当位置已经存在时?当它不存在时?两者都有?@Pascal两者都有。我尝试保存位置以供检查。但这也会在位置表中创建重复项。
if(dbLoc==null) {
dbLoc = new Location();
dbLoc.setLatitude(loc.getLatitude());
dbLoc.setLongitude(loc.getLongitude());
r.setParent(dbLoc);
// add changes on the dbLoc here
eManager.merge(r); // here you're merging r and the dbLoc
//loc.setLastModifiedDate(r.getMtime()); // why are you modifying the line from the file?
//loc.setWindDirection(r.getWindDirection());
//loc.setWindSpeed(r.getWindSpeed());
//loc.setTemperature(r.getTemperature());
//eManager.persist(loc);
//System.out.println("Location id : "+loc.getId());
//eManager.merge(dbLoc); // here you're merging a transient dbLoc again
}
public Location saveLocation(Location loc) {
eManager.clear();
eManager.setFlushMode(FlushModeType.COMMIT);
//eManager.setFlushMode(FlushModeType.COMMIT);
Query q = eManager.createNamedQuery("findLocationByLatLong");
q.setParameter("latitude", loc.getLatitude());
q.setParameter("longitude", loc.getLongitude());
try {
Location dummy = (Location) q.getSingleResult();
eManager.clear();
// eManager.flush();
return dummy;
} catch (NoResultException ex) {
Logger.getLogger("WeatherRecorderBean.class").log(Level.WARNING,
ex.getMessage());
eManager.clear();
eManager.merge(loc);
eManager.flush();
return loc;
} catch (Exception ex) {
Logger.getLogger("WeatherRecorderBean.class").log(Level.WARNING, "Should never get here! "+ex.getMessage());
return null;
}
}