Bypass GeneratedValue в спящем режиме (данные объединить не в db?)
Моя проблема такая же, как описано в [1] или [2]. Мне нужно вручную установить автоматически настроенное значение по умолчанию (зачем импортировать старые данные). Как описано в [1], используя Hibernate entity = em.merge(entity)
, этот трюк сделает.
К сожалению, для меня это не так. Я не получаю ошибку или никаких других предупреждений. Сущность просто не появится в базе данных. Я использую Spring и Hibernate EntityManager 3.5.3-Final.
Любые идеи?
Ответы
Ответ 1
он работает над моим проектом со следующим кодом:
@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();
}
}
где вы в основном определяете свой собственный генератор идентификаторов (на основе стратегии Identity), и если идентификатор не установлен, вы делегируете генерацию генератору по умолчанию.
Основной недостаток заключается в том, что он ограничивает вас Hibernate как провайдера JPA... но он отлично работает с моим проектом MySQL
Ответ 2
Другая реализация, проще.
Этот файл работает с и конфигурацией на основе аннотаций или xml: он полагается на метаданные спящего режима для получения значения id для объекта. Замените SequenceGenerator
на IdentityGenerator
(или любой другой генератор) в зависимости от вашей конфигурации. (Создание декоратора вместо подкласса, передача декодированного генератора идентификатора в качестве параметра этого генератора, остается в качестве упражнения для читателя).
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);
}
}
Отвечайте на упражнение (используя шаблон декоратора, по запросу), не проверенный на самом деле:
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);
}
}
Ответ 3
Обновление Laurent Grégoire отвечает за спящий режим 5.2, потому что, похоже, он немного изменился.
public class UseExistingIdOtherwiseGenerateUsingIdentity extends IdentityGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
return id != null ? id : super.generate(session, object);
}
}
и используйте его следующим образом: (замените имя пакета)
@Id
@GenericGenerator(name = "UseExistingIdOtherwiseGenerateUsingIdentity", strategy = "{package}.UseExistingIdOtherwiseGenerateUsingIdentity")
@GeneratedValue(generator = "UseExistingIdOtherwiseGenerateUsingIdentity")
@Column(unique = true, nullable = false)
protected Integer id;
Ответ 4
Я предлагаю решение, которое сработало для меня:
создайте свой собственный identifienerenerator/sequencegenerator
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()
Ответ 5
В соответствии с выборочно отключить создание нового идентификатора на форумах Hibernate, merge()
может быть не решением (по крайней мере не только), и вам, возможно, придется использовать настраиваемый генератор (это вторая ссылка, которую вы опубликовали).
Я не тестировал это сам, поэтому не могу подтвердить, но я рекомендую прочитать поток форумов Hibernate.
Ответ 6
Для всех, кто хочет это сделать, выше работает хорошо. Просто рекомендация получить идентификатор от объекта, а не наследование для каждого класса Entity (Just for 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 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);
}
}
Ответ 7
Вам нужна работающая транзакция.
Если ваша транзакция управляется вручную:
entityManager.getTransaction().begin();
(конечно, не забудьте зафиксировать)
Если вы используете декларативные транзакции, используйте соответствующее объявление (скорее всего, с помощью аннотаций)
Кроме того, установите уровень ведения журнала гибернации в debug
(log4j.logger.org.hibernate=debug
) в файле log4j.properties, чтобы отслеживать, что происходит более подробно.
Ответ 8
Если вы используете hibernate org.hibernate.id.UUIDGenerator
для генерации идентификатора строки, я предлагаю вам использовать:
public class UseIdOrGenerate extends UUIDGenerator {
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
Serializable id = session.getEntityPersister(null, object).getClassMetadata().getIdentifier(object, session);
return id != null ? id : super.generate(session, object);
}
}