如何使用条件删除NHibernate对象?

如何使用条件删除NHibernate对象?,nhibernate,criteria,Nhibernate,Criteria,这一定是个简单的问题。给定一个条件,如何删除满足该条件的实体 理由: HQL和NH标准是特定于NHibernate的构造,因此它们是服务器端DAL实现细节。我不希望他们“泄漏”到客户端。因此,我们的客户端提供LINQ表达式供服务器处理。到目前为止,select请求和LINQ到NHibernate的请求处理得很好 但是,现在需要实现批量删除操作。通常,客户端提供LINQ表达式,服务器将删除满足该表达式的实体。 不幸的是,LINQ to NHibernate在这里毫无帮助。它最多只能将给定的LINQ

这一定是个简单的问题。给定一个条件,如何删除满足该条件的实体

理由:

HQL和NH标准是特定于NHibernate的构造,因此它们是服务器端DAL实现细节。我不希望他们“泄漏”到客户端。因此,我们的客户端提供LINQ表达式供服务器处理。到目前为止,select请求和LINQ到NHibernate的请求处理得很好

但是,现在需要实现批量删除操作。通常,客户端提供LINQ表达式,服务器将删除满足该表达式的实体。 不幸的是,LINQ to NHibernate在这里毫无帮助。它最多只能将给定的LINQ表达式转换为NHibernate标准

无论如何,这就是故事。我想强调的是,客户端根本不知道NHibernate,我希望它保持这种方式

附言


我在您的存储库/dao/persistencemanager/任何类中使用NH 2.1

public IEnumerable<T> FindAll(DetachedCriteria criteria)

        {

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

        }
见戴维·布莱恩的帖子

编辑:


据我所知,如果要使用条件,则需要加载对象并对其进行迭代以删除它们。或者使用HQL或将SQL传递给会话。

您可以使用条件选择元素的ID,将它们连接成字符串,然后使用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);
}
public void Delete(ICriteria标准、字符串keyName、字符串tableName)
{
条件.setProjection(Projections.Attribute(keyName));
IList itemIds=criteria.List();
string collection=string.Join(“,”,Array.ConvertAll(itemIds,Convert.ToString));
HQL(string.Format(“delete from{0},where{1}in({2})”,tableName,keyName,collection);
}

这段代码没有经过测试或编译(特别是我不确定HQL部分),但我认为您已经明白了:由于投影,我们不会获取整个对象,而只获取索引。

简单地说,直到2.1.2,您无法获取


但是,如果您可以将LINQ表达式转换为HQL(或将ICriteria转换为HQL),那么您可以使用重载的
ISession.Delete()
方法,该方法使用传递的HQL字符串。

我知道这是一个老问题,但出于参数考虑;如果使用存储库模式,则可以声明一个执行以下操作的Delete方法:

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);
}
public void Delete(System.Linq.Expressions.Expression谓词)
{
var entities=_session.Query().Where(谓词);
foreach(实体中的var实体)
_删除(实体);
}

注意:代码使用表达式是为了使存储库接口足够通用,因此您也可以实现一个例如Entity Framework存储库。

我不喜欢这种方法,但在处理大量对象时,它需要先从数据库中获取所有实体,然后才能删除它们。这是真的,don“难道你不需要使用HQL来发出‘从何处删除’SQL语句吗?伙计们,你不是认真的。一定有更好的方法!但也有一种方法-可能不使用条件!好吧,可能可以将条件转换为HQL吗?这是否意味着要对数据库进行两次往返?如果是的话,那么这还不够好,因为本机SQL只需一次就可以完成。仍然如此。”比N+1更好…我想不出更好的使用标准的方法了:/I我知道我可以,但LINQ to NHibernate将LINQ转换为标准而不是HQL似乎并不奇怪,尽管后者应该更强大?也许它毕竟不是那么简单。我很想看到一个工作原型…我不会真的说HQL是mo它们只是两种不同的构造,通常有不同的用途:用于一次性特定查询的HQL和用于构建查询的准则,避免了所有字符串连接的麻烦,通过DetachedCriteria提供模块化支持,并且仍然更接近您的映射。by-example构造也很不错,但我n reality很少使用。无论如何,我还没有将LINQ用于nhibernate,因此我没有任何示例可以给出。然而,在新版本支持您所需的内容之前,标准仅适用于select语句。您要做的是使用表达式获取实体,然后逐个删除它们。这不是通过expre删除实体我的意思是拥有一个本机API,它接收一个表达式,将其转换为相应的delete SQL语句,然后一次性删除所有实体。这需要一个大的警告,当你有很多对象时,它是多么不好。
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);
}