绕过Hibernate中的GeneratedValue(合并数据不在数据库?)
我的问题与[1]或[2]中描述的相同。 我需要手动设置一个默认的自动生成的值( 为什么?导入旧数据 )。 正如在[1]中所描述的,使用Hibernate的entity = em.merge(entity)
将会做到这一点。
对我来说不幸的是, 我既没有错误,也没有任何其他的警告。 该实体不会出现在数据库中 。 我正在使用Spring和Hibernate EntityManager 3.5.3-Final。
有任何想法吗?
它使用下面的代码在我的项目上工作:
@XmlAttribute @Id @Basic(optional = false) @GeneratedValue(strategy=GenerationType.IDENTITY, generator="IdOrGenerated") @GenericGenerator(name="IdOrGenerated", strategy="....UseIdOrGenerate" ) @Column(name = "ID", nullable = false) private Integer id;
和
import org.hibernate.id.IdentityGenerator; ... public class UseIdOrGenerate extends IdentityGenerator { private static final Logger log = Logger.getLogger(UseIdOrGenerate.class.getName()); @Override public Serializable generate(SessionImplementor session, Object obj) throws HibernateException { if (obj == null) throw new HibernateException(new NullPointerException()) ; if ((((EntityWithId) obj).getId()) == null) { Serializable id = super.generate(session, obj) ; return id; } else { return ((EntityWithId) obj).getId(); } }
在那里你基本上定义了你自己的ID生成器(基于身份策略),如果ID没有设置,那么你可以把生成委派给默认的生成器。
主要的缺点是它将您绑定到Hibernate作为JPA提供程序…但它与我的MySQL项目完美协作
另一种实现方式比较简单。
这个可以同时使用基于注解和基于xml的configuration:它依靠hibernate元数据来获取对象的id值。 用IdentityGenerator
(或任何其他生成器)replaceSequenceGenerator
,具体取决于您的configuration。 (创build一个装饰器而不是子类,将装饰的ID生成器作为parameter passing给这个生成器,这是读者的一个练习)。
public class UseExistingOrGenerateIdGenerator extends SequenceGenerator { @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : super.generate(session, object); } }
练习的答案(使用装饰者模式,按要求),没有真正的testing:
public class UseExistingOrGenerateIdGenerator implements IdentifierGenerator, Configurable { private IdentifierGenerator defaultGenerator; @Override public void configure(Type type, Properties params, Dialect d) throws MappingException; // For example: take a class name and create an instance this.defaultGenerator = buildGeneratorFromParams( params.getProperty("default")); } @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : defaultGenerator.generate(session, object); } }
根据在Hibernate论坛上select性地禁止生成一个新的ID线程, merge()
可能不是解决scheme(至less不是单独的),你可能不得不使用自定义生成器 (这是你发布的第二个链接)。
我没有自己testing,所以我不能确认,但我build议阅读Hibernate论坛的主题。
对于其他人想要做到这一点,上面确实很好地工作。 只是build议从对象中获取标识符,而不是为每个实体类(仅用于Id)inheritance,您可以执行如下操作:
import org.hibernate.id.IdentityGenerator; public class UseIdOrGenerate extends IdentityGenerator { private static final Logger log = Logger.getLogger(UseIdOrGenerate.class .getName()); @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { if (object == null) throw new HibernateException(new NullPointerException()); for (Field field : object.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Id.class) && field.isAnnotationPresent(GeneratedValue.class)) { boolean isAccessible = field.isAccessible(); try { field.setAccessible(true); Object obj = field.get(object); field.setAccessible(isAccessible); if (obj != null) { if (Integer.class.isAssignableFrom(obj.getClass())) { if (((Integer) obj) > 0) { return (Serializable) obj; } } } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } } return super.generate(session, object); } }
你需要一个运行的事务。
如果您的交易是手动pipe理的:
entityManager.getTransaction().begin();
(当然不要忘记提交)
如果您正在使用声明性交易,请使用适当的声明(最有可能通过注释)
另外,在你的log4j.properties中设置hibernate日志级别为debug
( log4j.logger.org.hibernate=debug
),以便跟踪更多细节中发生的事情。
我在这里给我一个解决scheme:
创build你自己的识别者/序列生成器
public class FilterIdentifierGenerator extends IdentityGenerator implements IdentifierGenerator{ @Override public Serializable generate(SessionImplementor session, Object object) throws HibernateException { // TODO Auto-generated method stub Serializable id = session.getEntityPersister(null, object) .getClassMetadata().getIdentifier(object, session); return id != null ? id : super.generate(session, object); } }
修改您的实体为:
@Id @GeneratedValue(generator="myGenerator") @GenericGenerator(name="myGenerator", strategy="package.FilterIdentifierGenerator") @Column(unique=true, nullable=false) private int id; ...
而保存而不是使用persist()
使用merge()
或update()