Ответ 1
Используйте вот так
@SQLDelete(sql = "UPDATE {h-schema}LEAVE SET STATUS = 'DELETED' WHERE id = ?", check = ResultCheckStyle.COUNT)
Я пытаюсь использовать аннотацию @SQLDelete
Hibernate для мягкого удаления. Он хорошо работает, когда схема БД статична, т.е. Передает ее в SQL.
К сожалению, кажется, что SQL передан как EntityPersister
(cf EntityClass
method CustomSQL createCustomSQL(AnnotationInstance customSqlAnnotation)
, поэтому я не могу найти способ передать имя схемы динамически, как в исходных SQL-запросах, используя {h-schema}
Кто-нибудь нашел хорошее обходное решение для этой проблемы (я использую Hibernate 4.3.5)?
Изменить: если не существует реального решения, я в конечном итоге изменил исходный код кода org.hibernate.persister.entity.AbstractEntityPersister
, заменив заполнитель схемы при настройке пользовательских SQL-запросов в методе doLateInit
.
Edit2. Я создал проблему для этого поведения в Hibernate JIRA. Я создам запрос на перенос позже сегодня, и я хочу, чтобы команда Hibernate приняла его
Используйте вот так
@SQLDelete(sql = "UPDATE {h-schema}LEAVE SET STATUS = 'DELETED' WHERE id = ?", check = ResultCheckStyle.COUNT)
Как указано автором ниже:
В настоящее время я работаю над приложением Seam, которое нуждается в мягких удалениях в базе данных. Справа вы можете увидеть фрагмент моей диаграммы базы данных, содержащий таблицу CUSTOMER
и APP_USER
. Это просто одностороннее отношение, но важно отметить, что это поле "DELETED" в каждой таблице. Это поле, которое будет использоваться для отслеживания мягкого удаления. Если поле содержит '1, запись была удалена, и если она содержит' 0, запись не была удалена.
До ORM, таких как Hibernate, мне пришлось бы отслеживать и устанавливать этот флаг самостоятельно с помощью SQL. Было бы очень сложно сделать, но кто хочет написать кучу кода шаблона, чтобы отслеживать, была ли удалена запись. Здесь спящий режим и аннотации приходят на помощь.
Ниже приведены 2 класса Entity, которые были сгенерированы Hibernate, используя шов. Я пропустил части кода для ясности.
//Package name...
//Imports...
@Entity
@Table(name = "CUSTOMER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE customer SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@Where(clause="deleted <> '1'")
public class Customer implements java.io.Serializable {
private long id;
private Billing billing;
private String name;
private String address;
private String zipCode;
private String city;
private String state;
private String notes;
private char enabled;
private char deleted;
private Set appUsers = new HashSet(0);
// Constructors...
// Getters and Setters...
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "customer")
// Filter added to retrieve only records that have not been soft deleted.
@Where(clause = "deleted <> '1'")
public Set getAppUsers() {
return this.appUsers;
}
public void setAppUsers(Set appUsers) {
this.appUsers = appUsers;
}
}
//Package name...
//Imports...
@Entity
@Table(name = "APP_USER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE app_user SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@Where(clause="deleted <> '1'")
public class AppUser implements java.io.Serializable {
private long id;
private Customer customer;
private AppRole appRole;
private char enabled;
private String username;
private String appPassword;
private Date expirationDate;
private String firstName;
private String lastName;
private String email;
private String phone;
private String fax;
private char deleted;
private Set persons = new HashSet(0);
// Constructors...
// Getters and Setters...
}
Следующие два шага - все, что я должен был сделать для реализации мягкого удаления.
@SQLDelete
, которая переопределяет значение по умолчанию
Hibernate delete для этого объекта.@Where
для фильтрации запросов и возврата
записи, которые были мягко удалены. Отметим также, что в
Класс CUSTOMER добавил @Where
в коллекцию appUsers. Это
необходимо получить только приложения для этого клиента, у которых нет
был мягко удален.Viola! Теперь, когда вы удаляете эти объекты, он установит поле "DELETED" в поле "1" и при запросе этих объектов он будет возвращать только записи, содержащие "0 в " УДАЛИТЬ ".
Трудно поверить, но это все, что нужно для реализации мягких удалений с использованием аннотаций Hibernate.
также отметим, что вместо использования операторов @Where(clause="deleted ‘1’")
вы можете использовать фильтр hibernate (http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#entity-hibspec-filters), чтобы глобально отфильтровывать все удаленные объекты. Я обнаружил, что определение 2 менеджеров сущностей ("обычный, который фильтрует удаленные элементы, а другой, который не подходит для редких случаев...), обычно довольно удобен.
Вы можете создать DeleteEventListener
, например:
public class SoftDeleteEventListener extends DefaultDeleteEventListener {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void onDelete(DeleteEvent event, Set arg1) throws HibernateException {
Object o = event.getObject();
if (o instanceof SoftDeletable) {
((SoftDeletable)o).setStatusId(1);
EntityPersister persister = event.getSession().getEntityPersister( event.getEntityName(), o);
EntityEntry entityEntry = event.getSession().getPersistenceContext().getEntry(o);
cascadeBeforeDelete(event.getSession(), persister, o, entityEntry, arg1);
cascadeAfterDelete(event.getSession(), persister, o, arg1);
} else {
super.onDelete(event, arg1);
}
}
}
переместите его в свой persistence.xml, как этот
<property name = "hibernate.ejb.event.delete" value = "org.something.SoftDeleteEventListener"/>
Кроме того, не забудьте обновить свои каскады в своих аннотациях.