我有一个带有2个自动增量字段的表(PostgreSQL),第一个用@Id和@GeneratedValue注释,第二个应该自动递增并保存,直到我故意设置它。
有没有办法做到这一点?
@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。
答案 0 :(得分:1)
混合自动增量和手动值不是一个好主意。当你的当前序列指向11时,你应该如何插入一个值为20的条目?一旦序列达到20,您将获得唯一约束违规。为了防止这种情况,您必须验证生成的序列值是否与任何现有条目冲突 - 这将引入重试,锁定等所有其他问题。
重新考虑您的模型或要求可能是个好主意,为什么第二个伪Id?为什么要手动和自动填充它?
如果您坚持使用此功能,如果您保证,手动条目不会与自动生成的条目冲突,您可以使其正常工作。然后你可以为你的真实ID“列(整数id)创建一个自定义ID生成器并覆盖generate
方法,这样除了生成ID之外,你还要检查你的,伪Id的值”( routeNumberId)。如果是null
,您可以要求DB从某个序列中为您提供下一个值。虚拟实现如下:
@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查找,但首先要重新考虑您尝试实现的目标。
编辑:功能Id生成器代码(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;
}