2017-02-14 7 views
-1

У меня есть таблица (PostgreSQL) с 2 полями автоматического увеличения, первая из них аннотируется с @Id и @GeneratedValue, вторая должна быть автоматической увеличивайте и сохраняйте его, пока я не установлю его специально.Hibernate аннотации для автоматического приращения, но также следует сохранить значение, если мы установили его перед сохранением

Есть ли способ сделать это?

@Entity 
@Table(name = "route") 
public class Route extends BaseEntity { 

private Integer id; 
private Integer routeNumberId; 

@Id 
@GeneratedValue(strategy = GenerationType.IDENTITY) 
@Column(name = "id") 
public Integer getId() { 
    return id; 
} 
... 
@XmlAttribute 
@Id 
@Basic(optional = false) 
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="route_number_seq") 
@GenericGenerator(name="route_number_seq", 
        strategy="com.tripms.models.master.UseIdOrGenerate") 
@Column(name = "route_number_id", nullable = false) 
public Integer getRouteNumberId() { 
    return routeNumberId; 
} 

} 

Я не могу аннотировать @Id дважды, и мне не нужен составной pk.

+1

Вы пытались что-то кодировать? – msagala25

+1

Добро пожаловать в StackOverflow. Вы должны опубликовать код, чтобы показать свои усилия в отношении того, чего вы пытаетесь достичь. Это также поможет другим пользователям ответить на ваш вопрос. –

+0

Я обновил его. @SouravGhosh –

ответ

1

Смешивание автоинкремента и ручных значений - не очень хорошая идея. Как должна вести себя ваша база данных, когда ваша текущая последовательность указывает на 11, но вы вставляете запись со значением 20? Как только последовательность достигнет 20, вы получите уникальное нарушение ограничений. Чтобы предотвратить это, вам нужно будет убедиться, что генерируемое значение последовательности не противоречит какой-либо существующей записи, - которая собирается ввести целую кучу других проблем с повторением, блокировкой и т. Д.

Это может быть хорошей идеей переосмыслить свою модель или требования, почему вы второй псевдо Id? И почему это можно заполнить как вручную, так и автоматически? , если вы настаиваете на этой функции, вы можете заставить ее работать, если вы гарантируете, что записи вручную не сталкиваются с автогенерированными. Затем вы можете создать собственный генератор идентификаторов для своего столбца «истинный идентификатор» (Integer id) и переопределить метод generate, так что помимо генерации идентификатора вы также проверяете значение вашего псевдонима «(идентификатор маршрута)» (routeNumberId). Если это null, вы можете попросить БД дать вам следующее значение из некоторой последовательности. Фиктивная ниже реализация:

@Override 
public synchronized Serializable generate(SessionImplementor session, Object object) throws HibernateException { 
    Serializable result; 
    if (object instanceof Route) { 
     Route reoute= ((Route) object); 
     if (route.getid() != null) { 
      result = (Serializable) route.getId(); 
     } else { 
      result = <GENERATE new ID(e.g. call super, etc)> ; 
     } 
     if (route.getRouteNumberId() == null) { 
      long autoIncrRouteId = <GENERATE new routeID,> 
      route.setRouteNumberId(autoIncrRouteId); 
     } 
     return result; 
    } else { 
     result = super.generate(session, object); 
    } 

    return result; 
} 

Другой вариант заключается в использовании @PrePersist сущности слушателя и сделать чек и/или последовательность вызова там. Однако было бы сложно получить доступ к диспетчеру сущностей или контексту JPA от слушателей, так как большинство поставщиков JPA не полностью поддерживают инъекцию в слушатели сущностей. Вы можете выполнить ручной поиск jndi, но сначала переосмыслите то, что вы пытаетесь достичь, если это того стоит.

Редактировать: функциональный код генератора кода (postgres).

@Override 
public Serializable generate(SessionImplementor session, Object obj) throws HibernateException { 
    Connection connection = session.connection(); 
    try { 
     Route route= ((Route) obj); 
     String seqName = "you_db_id_sequence"; 
     PreparedStatement ps = connection.prepareStatement("SELECT nextval ('" + seqName + "') as nextval"); 
     ResultSet rs = ps.executeQuery(); 
     if (rs.next()) { 
      int id = rs.getInt("nextval"); 
      log.info("Generated order id {} ", id); 
      if (route.getRouteNumberId() == null) { 
       route.setrouteNumberid(id); //or call another sequence to get a different id 
      } 
      return Long.parseLong(code); 
     } else { 
      throw new IllegalStateException("could not generate new id"); 
     } 
    } catch (SQLException e) { 
     log.error("Could not generate id!", e); 
     throw new HibernateException("Unable to generate id from Sequence"); 
    } 
    return null; 
} 
+0

Причина, по которой я хочу, чтобы routeNumberId мог добавить вручную -> пока сохраняются записи маршрута, оба должны автоматически увеличивать .. и есть одно условие, когда мне нужно сделать целую копию запись с тем же маршрутомNumberId (coz это Fk для других таблиц), а также нужна предыдущая запись для аудитов, а также будет хранить старые записи routeNumberId в другом столбце .. поэтому он не даст проблемы u, упомянутой об уникальном нарушении ограничений coz в любом случае i будет использовать routeNumberId, который уже сгенерирован. –

+0

код u дал выше, работает только для Id .... мне нужно это для routeNumberId .. он не будет работать на routeNumberId coz i, это позволяет мне аннотировать @ Id на обоих из них. этот код работает, если аннотируется только с @ Id –

+0

Если routeNumberId является FK для другой таблицы, то он должен быть ассоциацией '@ OneToOne' или' @ ManyToOne', а не автоматически увеличивающимся целым числом , Предоставленный код будет заполнять как Id, так и routeNumberId, даже если генератор - это только поле Integer Id. Конечно, у вас не может быть двух столбцов, аннотированных с помощью '@ Id', если вы не хотите составной ПК. В любом случае, если routeNumberId является FK для другого объекта, то ваша модель должна отражать это. – yntelectual