Как справиться с JPA многие-к одними отношениями?

StackOverflow https://stackoverflow.com/questions/3825662

  •  26-09-2019
  •  | 
  •  

Вопрос

Я проектирую приложение для сбора данных о погоде. У меня есть 2 объекта POJO "Расположение" и "запись". Местоположение содержит информацию о широте и долготе и текущих погодных условиях, а запись содержит всю информацию о погоде со временем для определенного местоположения, имеющего отношение много к одному с местоположением. Определение классов у меня есть следующее:

Расположение.java.java.

@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

Теперь, когда я получаю запись, я хочу вставить его в таблицу записи. И, как у меня есть внешний ключ к месту, я также добавлю таблицу местоположения местоположения. Еще одна вещь, таблица местоположения не преподается. Поэтому, когда приходит новая запись, я впервые вставляю его в таблицу местоположения, а затем заполните таблицу записи с внешним ключом. И я не хочу дублирование записей местоположения в таблице местоположения. Таблица местоположения также будет содержать самую последнюю температуру, ветровые последствия и данные Winddirection, как вы можете увидеть.

Я использую следующий код для достижения этого:

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);

}

Но, делая это, то, что происходит, являются дублируемыми местами. Это означает, что у меня есть несколько записей для такой же долготы и широты, но с различной температурой, данные ветра в таблице местоположения. То, что я хочу достичь, у него есть единая запись на одну широту и долготу и обновлять поля ветра, температуры и ветчина с последними данными.

Пожалуйста помоги!

Это было полезно?

Решение 2

Решено :-)

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;
    }
}

Я создаю новую функцию для сохранения LocationОтказ У меня также было несколько проблем синхронизации. У меня была эта функция в MDB onMessage() функция. Итак до одного onMessage() Был закончен еще один начал, отсюда, создавая дубликаты записей!

Надеюсь, это поможет кому-то в будущем!

Другие советы

Ты каскадинг ALL Операции от Record к Location Так что, когда вы объединяете новый Record и его новый родитель Location, нет необходимости сливаться Location снова (или вы получите дубликаты строки).

Я положил несколько комментариев в вашем коде ниже (я не исправил все, есть ими больше проблем, но предлагаемые изменения должны по крайней мере удалить создание дубликатов Location Записи):

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

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top