2010-11-03 4 views
2

Je ne sais pas si c'est vraiment trivial à faire et je ne fais que compliquer les choses, mais j'y ai réfléchi pendant une bonne partie de la dernière heure.Comment "désactiver" une entité au lieu de la supprimer en utilisant NHibernate?

J'ai donc des entités. Par conséquent, NHibernate. Ce que je veux faire est de ne "désactiver" les entités que lorsque je veux les "supprimer", au lieu de les retirer physiquement de la base de données. (Juste parce que nous ne voulons pas vraiment supprimer les enregistrements de notre magasin de données).

Toutes mes entités héritent d'une classe BaseEntity avec une propriété BaseEntity.Active.

Ce que j'ai en cours d'exécution droit est maintenant quelque chose comme ce qui suit dans la classe d'entité fichier de mapping:

<sql-delete> 
UPDATE SomeEntityTable SET Active = 0 WHERE Id = ? 
</sql-delete> 

Cela fonctionne bien, sauf que je vais devoir injecter que, personnalisé avec la table name, dans chaque fichier de mappage HBM pour chaque entité (nous n'implémentons pas l'héritage BaseEntity dans aucune stratégie de sous-classement). Comme vous pouvez le voir, cela peut être un peu subalterne. Le codage serait fastidieux, la maintenance horrible, et déclarer le nom de la table deux fois dans le même fichier de mappage me frotte le mauvais sens.

Ce que je jouais plus tôt était de savoir si je pouvais ou non implémenter un écouteur d'événements; peut-être OnPreDelete ou quelque chose, et mettre à jour .Active propriété de l'entité, comme suit:

class BaseEventListener : IPreDeleteListener 
{ 
    public bool OnPreDelete(PreDeleteEvent @event) 
    { 
     BaseEntity be = @event.Entity as BaseEntity; 
     if (be != null) 
      be.Active = false; 

     return false; 
    } 
} 

De cette façon, l'ensemble thingy « de désactivation » est automatisé pour toutes les entités qui prennent en charge la désactivation. Le problème est, je pense que NHibernate construirait toujours une requête SQL DELETE appropriée qui brûlera mon entité du magasin de données de toute façon au lieu de mettre à jour la chose, donc ce sera gaspillé effort automagique.

Comment dois-je procéder?

Répondre

3

Vous pouvez utiliser un écouteur d'événement. Vous devez également ajouter l'écouteur à la configuration.

public class SoftDeleteEventListener : DefaultDeleteEventListener 
    { 
     protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) 
     { 
      var softDeletable = entity as BaseEntity; 
      if (softDeletable != null) 
      { 
       softDeletable.Active = false; 
      } 
      else 
      { 
       base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); 
      } 
     } 
    } 
+0

Ne devrais-je pas également mettre à jour cette entité en quelque sorte après le réglage .Active? Quelque chose comme session.SaveOrUpdate (softDeletable); ? –

+1

@Richard: cela ne serait pas nécessaire, nhibernate utiliserait un suivi incorrect pour déterminer qu'une mise à jour était nécessaire lorsque votre session a été vidée. – DanP

+0

Merci @Paco, @DanP. Je pense que je vais aller avec cela, et juste ajouter des appels explicites à 'CascadeBeforeDelete()' et 'CascadeAfterDelete()' dans le bloc conditionnel de suppression douce. –

2

Comme il est assez clair que vous ne supprimez jamais réellement vos entités persistantes (comme cela est le cas avec la plupart des applications), il n'y a pas besoin est d'utiliser la méthode Delete juste parce qu'il est là.

Une autre approche:

  • une entité Déclare base avec une Active propriété
  • Set à faux pour les cas d'utilisation "supprimer". Vous pouvez même ajouter une méthode Delete à votre entité de base qui ne vient que
  • Vous pouvez, en outre, create a filter pour éviter le chargement « supprimé » entités

Oui, il est un travail impliqué, mais dans la À long terme, c'est pour le mieux, car vous aurez toujours une implémentation maintenable et non-hacky.

Une partie de la charge peut être réduite si vous utilisez une approche de mappage basée sur les conventions + code, comme ConfORM ou Fluent.

+0

Bien qu'une implémentation comme celle-ci _definitely_ convienne mieux à mon palais, je cherche en fait à modifier le comportement actuel de suppression de NH pour tirer parti des mappages, de sorte que la suppression s'efface naturellement dans les relations de l'entité. La suggestion de filtre est vraiment très bien, et je suis sûr que je vais l'utiliser avec mon projet. Merci! +1 –

+0

Vous pourriez avoir votre méthode BaseEntity.Delete faire la cascade aussi ... Chaque entité spécifierait quelles collections mettre en cascade, et c'est tout. –

Questions connexes