2009-08-25 29 views
13

这必须是一个简单的问题。给定一个标准,如何删除满足标准的实体?如何使用条件删除NHibernate对象?

的基本原理:

HQL和NH标准是NHibernate的特定构建体和因此它们是服务器侧DAL实现细节。我不希望他们“泄漏”到客户端。所以,我们的客户端提供了LINQ表达式来处理服务器。直到现在,select请求和LINQ to NHibernate处理它们的请求都很好。

但是,现在需要实施批量删除操作。像往常一样,客户端提供一个LINQ表达式,服务器将删除满足该表达式的实体。 不幸的是,LINQ to NHibernate在这里没有任何帮助。它可以做的最多的是将给定的LINQ表达式转换为NHibernate标准。

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

P.S.

我使用NH 2.1

回答

-3

在你的资料库/刀/ 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); 

      } 

     } 

见戴维·布里翁的帖子Data Access with NHibernate

编辑

据我知道,如果你想使用标准,你需要加载的对象,并在它们之间迭代删除它们。或者使用HQL或将SQL传递给会话。

+6

虽然在处理大量对象时我不喜欢这种方法,因为它需要先从数据库中获取所有实体,然后才能删除它们。 – 2009-08-25 09:02:57

+3

这是真的,你不需要使用HQL来发出'DELETE FROM WHERE'SQL语句吗? – DanB 2009-08-25 09:05:50

+2

伙计们,你不认真。一定会有更好的办法! – mark 2009-08-25 09:06:26

7

您可以使用条件选择元素的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); 
} 

此代码是没有测试或编译(尤其是我不知道的HQL部分的),但我认为你得到了主意:我们不取整个物体归功于投影,但只有索引。

+1

这是否意味着数据库的两次往返?如果是的话,那么它不够好,因为原生SQL只是在一个中完成。 – mark 2010-06-18 11:04:52

+1

还是比N + 1更好......我不能用一个更好的方式来使用条件:/ – madprog 2010-07-06 10:12:28

3

简单地说,直到2.1.2你不能。但是,如果您可以将LINQ表达式转换为HQL(或ICriteria转换为HQL),那么您可以使用超载的ISession.Delete()方法,该方法使用传递的HQL字符串。

+0

我知道我可以,但是看起来奇怪的是LINQ to NHibernate将LINQ转换为Criteria而不是HQL,尽管后者是假设的更强大?可能这毕竟不是那么简单。我很想看到一个工作原型... – mark 2010-06-18 18:22:41

+0

我不会说HQL比Criteria更强大,反之亦然。它们只是两种不同的结构,通常具有不同的用途:HQL用于一次性特定查询和构建查询的标准,避免了所有字符串连接的麻烦,通过DetachedCriteria进行模块化支持,并且仍然更接近您的映射。该示例构造也很甜,但实际上很少使用。总之,我不使用LINQ for nhibernate -yet-,所以我没有任何例子可以给。然而,直到一个新版本支持你想要的,标准只适用于选择语句 – Jaguar 2010-06-18 21:30:37

-5

我知道这是一个古老的问题,但为争辩的缘故;如果使用存储库模式,你可以声明删除方法,执行以下操作:

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

注意代码使用表达式,以便仓库接口足够通用的,所以你也可以实现例如实体框架库。

+4

不完全。你所做的是使用表达式来获取实体,然后逐个删除它们。这不是通过表达式删除实体。我的意思是有一个接收表达式的本地API,将它转换为相应的删除SQL语句,然后一次删除所有实体。 – mark 2011-08-20 05:19:09

+2

这需要一个很大的警告,说明当你有很多对象时它不会很好。 – 2013-04-18 18:08:02