2009-01-29 9 views
33

Pour que mes tests d'intégration restent indépendants, j'enlève toutes les anciennes données et j'insère de nouvelles données de test avant chaque test. Existe-t-il une meilleure façon de procéder que de simplement interroger toutes les entités et de les supprimer une par une?La meilleure façon de supprimer toutes les lignes d'une table en utilisant NHibernate?

J'ai envisagé d'écrire un proc stocké qui exécute "delete from nom de table;" pour chaque table à effacer. Cela devrait être un peu plus rapide, mais ce serait bien de le faire sans faire de requêtes SQL ou d'appeler les SP via NH. J'utilise NHibernate vanille et Linq NHibernate. Je crois que Castle Active Record a quelque chose comme Foo.DeleteAll(), mais je ne veux pas utiliser Active Record pour ce projet.

Des idées?

Merci/Erik

MISE À JOUR:

Comme cette question a été posée et a répondu, des progrès ont été réalisés par l'équipe NHibernate. Comme Ayende l'explique dans this blog post, vous pouvez maintenant exécuter des requêtes DML directement, sans que NHibernate n'ait à chercher des entités.

Pour supprimer tous les Foo objets que vous pouvez faire comme ceci:

using (ISession session = ...) 
using (ITransaction transaction = session.BeginTransaction()) 
{ 
    session.CreateQuery("delete Foo f").ExecuteUpdate(); 

    transaction.Commit(); 
} 

Cette requête générerait l'instruction SQL suivante:

delete from Foo 

qui Aught d'être nettement plus rapide que la récupération des entités d'abord, puis les supprimer. Attention cependant, puisque les requêtes comme celles-ci n'affectent pas le cache de niveau 1.

+2

Si vous utilisez SQL Server, il est BEAUCOUP plus efficace d'exécuter TRUNCATE TABLE foo; 'car il s'agit d'une opération journalisée minimale. L'exécution de 'DELETE FROM foo;' enregistre toutes les suppressions à des fins de récupération; Sur les grandes tables, cela nécessite un disque/temps important. –

+3

TRUNCATE TABLE n'est presque jamais disponible lorsqu'il y a des clés étrangères impliquées. –

Répondre

32

Dans le TearDown de mes UnitTests, je fais surtout ceci:

using(ISession s = ...) 
{ 
    s.Delete ("from Object o"); 
    s.Flush(); 
} 

Cela devrait supprimer toutes les entités. Si vous voulez supprimer toutes les instances d'une entité spécifique, vous pouvez le faire:

using(ISession s = ....) 
{ 
    s.Delete ("from MyEntityName e"); 
    s.Flush(); 
} 

Offcourse, il y a un inconvénient avec cette méthode, et qui est que NHibernate va d'abord chercher les entités avant de les supprimer.

+0

Oh, j'avais complètement manqué que vous pouvez passer une requête à session.Delete(). Merci! –

+7

BTW: C'est mortellement lent sur les grandes tables –

+0

INdeed, c'est l'inconvénient que j'ai mentionné. –

10

J'utilise Fluent NHibernate attributs donc je modifier le code un peu pour ne pas hardcore noms de table

private static void CleanUpTable<T>(ISessionFactory sessionFactory) 
{ 
    var metadata = sessionFactory.GetClassMetadata(typeof(T)) as NHibernate.Persister.Entity.AbstractEntityPersister; 
    string table = metadata.TableName; 

    using (ISession session = sessionFactory.OpenSession()) 
    { 
     using (var transaction = session.BeginTransaction()) 
     { 
      string deleteAll = string.Format("DELETE FROM \"{0}\"", table); 
      session.CreateSQLQuery(deleteAll).ExecuteUpdate(); 

      transaction.Commit(); 
     } 
    } 
} 

utilisation

CleanUpTable<Person>(sessionFactory); 
+0

J'ai décidé de ne pas éditer cette question parce que "hardcore" sonne beaucoup mieux que "hardcode", même si c'est ce dernier qui était probablement destiné. –

1

Avec NHibernate 5.0, vous pouvez maintenant simplement faire:

session.Query<Foo>().Delete(); 

Documentation:

// 
    // Summary: 
    //  Delete all entities selected by the specified query. The delete operation is 
    //  performed in the database without reading the entities out of it. 
    // 
    // Parameters: 
    // source: 
    //  The query matching the entities to delete. 
    // 
    // Type parameters: 
    // TSource: 
    //  The type of the elements of source. 
    // 
    // Returns: 
    //  The number of deleted entities. 
    public static int Delete<TSource>(this IQueryable<TSource> source); 
Questions connexes