2009-08-25 23 views
13

Esto debe ser una pregunta simple. Dado un criterio, ¿cómo se eliminan las entidades que satisfacen los criterios?¿Cómo se pueden eliminar objetos NHibernate utilizando un criterio?

La razón de ser:

HQL y criterios NH son NHibernate construcciones específicas y como tales son de servidor DAL lado detalles de implementación. No quiero que se "filtren" al lado del cliente. Por lo tanto, nuestro lado del cliente proporciona expresiones LINQ para que el servidor las procese. Hasta ahora, las solicitudes en las que se seleccionaban solicitudes y LINQ a NHibernate trataban muy bien.

Sin embargo, ahora es necesario implementar la operación de eliminación por lotes. Como es habitual, el lado del cliente proporciona una expresión LINQ y el servidor elimina entidades que satisfacen la expresión. Desafortunadamente, LINQ to NHibernate no es de ayuda aquí. Lo máximo que puede hacer es traducir la expresión LINQ dada a los criterios NHibernate.

De todos modos, esta es la historia. Deseo enfatizar que el lado del cliente no tiene conocimiento de NHibernate y me gusta que siga así.

P.S.

estoy usando NH 2.1

Respuesta

-3

En su repositorio/DAO/PersistenceManager/cualquier clase:

public IEnumerable<T> FindAll(DetachedCriteria criteria) 

     { 

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

     } 

y luego puesto

public void Delete(DetachedCriteria criteria) 

     { 

      foreach (T entity in FindAll(criteria)) 

      { 

       Delete(entity); 

      } 

     } 

Ver Davy de Brion Data Access with NHibernate.

Edición:

Por lo que yo sé, si desea utilizar criterios que necesita para cargar los objetos e iterar sobre ellos para eliminarlos. Alternativamente, use HQL o pase el SQL a la sesión.

+6

No me gusta este método, sin embargo, cuando se trabaja con un gran número de objetos, ya que primero es necesario recuperar todas las entidades de la base de datos para poder eliminarlas. –

+3

Esto es cierto, ¿no tienes que usar HQL para emitir una instrucción SQL 'DELETE FROM WHERE'? – DanB

+2

Chicos, no habla en serio. ¡Debe haber una mejor manera! – mark

7

Puede usar los criterios para seleccionar los ID de sus elementos, unirlos en una cadena y usar HQL para eliminarlos?

Algo así como:

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

Este código no ha sido probado o compilado (en particular, no estoy seguro de la sección HQL), pero creo que tienes la idea: no buscar el objetos enteros gracias a la proyección, pero solo a los índices.

+1

¿Significa dos viajes de ida y vuelta a la base de datos? Si es así, entonces no es lo suficientemente bueno, porque SQL nativo lo hace simplemente en uno. – mark

+1

Aún mejor que N + 1 ... No puedo encontrar una mejor manera usando los criterios:/ – madprog

3

En pocas palabras, hasta 2.1.2 no se puede.

Sin embargo, si puede traducir la expresión LINQ a HQL (o la ICriteria a HQL) entonces puede usar el método ISession.Delete() sobrecargado que utiliza una cadena HQL pasada.

+0

Sé que puedo, pero no parece extraño que LINQ a NHibernate traduzca LINQ a Criteria en lugar de a HQL, aunque se supone que esto último ser más poderoso? Puede ser que no es tan simple después de todo. Me encantaría ver un prototipo funcional ... – mark

+0

No diría que HQL es más poderoso que Criteria, o viceversa. Son solo dos construcciones diferentes, generalmente con diferentes propósitos: HQL para consultas específicas de una sola vez y criterios para crear consultas que evitan todas las complicaciones de concatenación de cadenas, soporte modular a través de DetachedCriteria y aún estar más cerca de su mapeo. La construcción por ejemplo también es dulce, pero en realidad rara vez se usa. De todos modos, no estoy usando LINQ para nhibernate, así que no tengo ningún ejemplo para dar. Sin embargo, hasta que una versión más reciente admita lo que desea, los Criterios son solo para declaraciones seleccionadas – Jaguar

-5

Sé que esta es una vieja pregunta, pero por el bien de los argumentos; si se utiliza el patrón repositorio, puede declarar un método de eliminación, que hace lo siguiente:

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

Nota el código está utilizando expresiones con el fin de interfaz de repositorio para ser lo suficientemente generales como para que también pueda implementar una por ejemplo repositorio de Entity Framework.

+4

No del todo. Lo que debes hacer es usar una expresión para buscar las entidades y luego eliminarlas una a una. Esto no es eliminar entidades por expresión. Lo que quiero decir es tener una API nativa que recibe una expresión, la convierte a la respectiva instrucción SQL de eliminación y luego elimina todas las entidades de una vez. – mark

+2

Esto necesita una gran advertencia acerca de cómo no va a ser bueno cuando tienes muchos objetos. –

Cuestiones relacionadas