Как удалить объекты NHibernate с использованием критериев?

Это должен быть простой вопрос. Учитывая критерии, как удалить объекты, удовлетворяющие критериям?

Обоснование:

Критерии HQL и NH являются специфичными для NHibernate конструкциями, и поэтому они являются деталями реализации DAL на стороне сервера. Я не хочу, чтобы они "просачивались" на клиентскую сторону. Таким образом, наша клиентская сторона предоставляет выражения LINQ для обработки сервера. До сих пор запросы, в которых запросы на выбор и LINQ to NHibernate имели дело с ними, были прекрасными.

Однако теперь необходимо выполнить операцию пакетного удаления. Как обычно, клиентская сторона предоставляет выражение LINQ, и сервер должен удалить объекты, удовлетворяющие выражению. К сожалению, LINQ to NHibernate здесь не поможет. Самое большее, что он может сделать, это перевести данное выражение LINQ в критерии NHibernate.

Во всяком случае, это история. Я хочу подчеркнуть, что клиентская сторона вообще не знает об NHibernate, и мне нравится, чтобы это было так.

P.S.

Я использую NH 2.1

Ответ 1

Вы можете использовать критерии для выбора идентификаторов ваших элементов, объединения их в строку и использования HQL для их удаления?

Что-то вроде:

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);
}

Этот код не был протестирован или не скомпилирован (в частности, я не уверен в разделе HQL), но я думаю, что у вас есть идея: мы не получаем все объекты благодаря проекции, но только индексы.

Ответ 2

Проще говоря, до 2.1.2 вы не можете.

Однако, если вы можете перевести выражение LINQ на HQL (или ICriteria на HQL), вы можете использовать перегруженный метод ISession.Delete(), который использует переданную строку HQL.

Ответ 3

В вашем репозитории/dao/persistencemanager/любом классе:

public IEnumerable<T> FindAll(DetachedCriteria criteria)

        {

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

        }

а затем

public void Delete(DetachedCriteria criteria)

        {

            foreach (T entity in FindAll(criteria))

            {

                Delete(entity);

            }

        }

См. сообщение Дэви Бриона Доступ к данным с NHibernate.

Edit:

Насколько я знаю, если вы хотите использовать критерии, вам нужно загрузить объекты и перебрать их, чтобы удалить их. В качестве альтернативы можно использовать HQL или передать SQL в сеанс.

Ответ 4

Я знаю, что это старый вопрос, но для аргументации; если вы используете шаблон репозитория, вы можете объявить метод удаления, который выполняет следующие действия:

public void Delete(System.Linq.Expressions.Expression<System.Func<TEntity, bool>> predicate)
{
    var entities = _session.Query<TEntity>().Where(predicate);
    foreach (var entity in entities)
        _session.Delete(entity);
}

Обратите внимание, что код использует выражения для того, чтобы интерфейс репозитория был достаточно общим, чтобы вы могли также реализовать, например, репозиторий Entity Framework.