views:

1415

answers:

3

Dear ladies and sirs.

This must be a simple question. Given a criteria, how one deletes the entities satisfying the criteria?

The rationale:

HQL and NH criteria are NHibernate specific constructs and as such they are server side DAL implementation details. I do not want them to "leak" to the client side. So, our client side provides LINQ expressions for the server to process. Up until now the requests where select requests and LINQ to NHibernate dealed with them just fine.

However, there is a need to implement batch delete operation now. As usual, the client side provides a LINQ expression and the server is to delete entities satisfying the expression. Unfortunately, LINQ to NHibernate is of no help here. The most it can do is translate the given LINQ expression to NHibernate criteria.

Anyway, this is the story. I wish to stress that the client side is unaware of NHibernate at all and I like it to stay this way.

Thanks.

P.S.

I am using NH 2.1

+1  A: 

In your repository/dao/persistencemanager/whatever class:

public IEnumerable<T> FindAll(DetachedCriteria criteria)

        {

            return criteria.GetExecutableCriteria(Session).List<T>();

        }

and then

public void Delete(DetachedCriteria criteria)

        {

            foreach (T entity in FindAll(criteria))

            {

                Delete(entity);

            }

        }

See Davy Brion's post Data Access with NHibernate.

Edit:

As far as I know, if you want to use Criteria you need to load the objects and iterate over them to delete them. Alternatively use HQL or pass in the SQL to the session.

DanB
I don't like this method though when working with large numbers of objects as it requires fetching all the entities from the database first before they can be deleted.
KeeperOfTheSoul
This is true, don't you have to use HQL to issue a 'DELETE FROM WHERE' SQL statement?
DanB
Guys, you are not serious. There must be a better way!
mark
There is - AFAIK not using Criteria though!
DanB
Well, may be it is possible to convert Criteria to HQL?
mark
@mark: DanB has it right. HQL and Criteria each have its pros and cons. Each has its time and place. For batch updating/deleting use HQL.
Mauricio Scheffer
I have added a detailed rationale for wanting what I want in the body of my question.
mark
+1  A: 

You may use the criteria to select the IDs of your elements, join them in a string and use HQL to delete them?

Something like:

public void Delete(ICriteria criteria, string keyName, string tableName)
{
    criteria.setProjection(Projections.Attribute(keyName));
    IList<int> itemIds = criteria.List<int>();

    string collection = string.Join(",", Array.ConvertAll<int, string>(itemIds, Convert.ToString));

    Session.HQL(string.Format("delete from {0} where {1} in ({2})", tableName, keyName, collection);
}

This code was not tested or compiled (in particular I'm not sure of the HQL section), but I think that you got the idea: we don't fetch the whole objects thanks to the projection, but only the indices.

madprog
Does it mean two round-trips to the database? If yes, then it is not good enough, because native SQL does it simply in one.
mark
Still better than N+1… I can't figure a better way using criteria :/
madprog
+1  A: 

Simply put, up until 2.1.2 you cannot.

However, if you can translate the LINQ expression to HQL (or the ICriteria to HQL) then you can use the overloaded ISession.Delete() method which uses a passed HQL string.

Jaguar
I know I can, but does it not seem strange that LINQ to NHibernate translates LINQ to Criteria instead of to HQL, although the latter is supposed to be more powerful? May be it is not that simple after all. I would love to see a working prototype...
mark
i wouldn't really say that HQL is more powerful than Criteria, or vice versa. They are just two different constructs, usually with different purposes: HQL for one-off specific queries and criteria for building queries avoiding all the string concatenation hassle, modular support via DetachedCriteria and still being closer to your mapping. The by-example construct is also sweet but in reality rarely used. Anyhow, i'm not using LINQ for nhibernate -yet- so i don't have any examples to give. Nevertheless, until a newer version supports what you want, Criteria are only for select statements
Jaguar