views:

83

answers:

6

Is it possible to delete all data in the database using NHibernate. I want to do that before starting each my unittests. Currently I drop my database and create it again but this is not acceptable solution for me.

========================================================== ok, here are the results. I am testing this on one database (Postgre). I will test CreateSchema(1), DanP solution(2) and apollodude217 solution(3). I run the tests 5 times with each method and take the average time.

Round 1 - 10 tests
(1) - ~26 sec
(2) - 9,0 sec
(3) - 9,3 sec

Round 2 - 100 tests
(1) - Come on, I will not do that on my machine
(2) - 12,6 sec
(3) - 18,6 sec

I think that it is not necessary to test with more tests.

A: 

I'm using the SchemaExport class and recreate the schema before each test. This is almost like dropping the database, but it's only dropping and recreating the tables. I assume that deleting all data from each table is not faster then this, it could even be slower.

Our unit tests are usually running on Sqlite in memory, this is very fast. This database exists only as long as the connection is open, so the whole database is recreated for each test. We're switching to Sqlserver by changing the build configuration.

Stefan Steinegger
Thanks, but as I said I do not want to drop the schema and recreate it. Also, I think that sqlite cannot be proper for persistence test. Lets do not discuss sqlite here please.
mynkow
There is no faster and safer solution that recreating the schema. You could also rollback changes instead of committing, but this doesn't work for us because we have multiple transactions within a test.
Stefan Steinegger
A: 

Re-creating the database is a good choice, especially for unit testing. If the creation script is too slow you could take a backup of the database and use it to restore the DB to an initial state before each test.

The alternative would be to write a script that would drop all foreign keys in the database then delete/truncate all tables. This would not reset any autogenerated IDs or sequences however. This doesn't seem like an elegant solution and it is definitely more time consuming. In any case, this is not something that should be done through an ORM, not just NHibernate.

Why do you reject the re-creation option? What are your requirements? Is the schema too complex? Does someone else design the database? Do you want to avoid file fragmentation?

Panagiotis Kanavos
Hi, I need speed for my unittests. I tested the performance when I just do drop/create database schema without any other logic and with increasing the number of unittest the performance is going down. If I do it with custom script which deletes all the data performance is acceptable. I just wandered if there is a way to do it automatically with NHibernate.
mynkow
Even if there was it would either recreate the DB or truncate the data. I'd guess you have a complex script and very little data in a subset of the tables, otherwise recreating the DB from script or backup would be faster. If that's the case, only you know which tables have to be truncated. You could put code in your teardown method to delete only the tables used in your test.
Panagiotis Kanavos
+1  A: 

I do not claim this is faster, but you can do something like this for each mapped class:

// untested
var entities = MySession.CreateCriteria(typeof(MappedClass)).List<MappedClass>();
foreach(var entity in entities)
    MySession.Delete(entity);  // please optimize

This (alone) will not work in at least 2 cases:

  1. When there is data that must be in your database when the app starts up.
  2. When you have a type where the identity property's unsaved-value is "any".
apollodude217
Yes, that is something that I wanted to see. I will test it and ping back here.
mynkow
Sorry, but I cannot mark to responses as an answer. Actually your suggestion is working but a bit slower. Thanks
mynkow
A: 

A good alternative is having a backup of the initial DB state and restoring it when starting tests (this can be complex or not, depending on the DB)

Diego Mijelshon
A: 

Another solution might be to create a stored procedure that wipes the data. In your test set up or instantiate method run the stored procedure first.

However I am not sure if this is quicker than any of the other methods as we don't know the size of database and number of rows likely to be deleted. Also I would not recommend deploying this stored procedure to the live server for safety purposes!

HTH

Rippo
Yes, if I work only on one database. In my case I am executing some tests on 5 different databases. :)
mynkow
+2  A: 

Personally, I use a stored procedure to do this, but it may be possible with Executable HQL (see this post for more details: http://fabiomaulo.blogspot.com/2009/05/nh21-executable-hql.html )

Something along the lines of session.Delete("from object");

DanP