2009-08-25 6 views
13

To musi być proste pytanie. Biorąc pod uwagę kryteria, w jaki sposób usuwa się podmioty spełniające kryteria?Jak można usunąć obiekty NHibernate za pomocą kryteriów?

Uzasadnieniem:

HQL i NH kryteria są NHibernate specyficzne konstrukcje i jako takie są one side DAL szczegóły implementacji serwera. Nie chcę, aby "wyciekły" do klienta. Tak więc, nasza strona klienta udostępnia wyrażenia LINQ dla serwera do przetworzenia. Do tej pory żądania, w których wybierały żądania i LINQ do NHibernate, działały z nimi dobrze.

Istnieje jednak konieczność wdrożenia operacji usuwania partii. Jak zwykle strona klienta udostępnia wyrażenie LINQ, a serwer usuwa elementy spełniające wyrażenie. Niestety, LINQ do NHibernate nie ma tutaj żadnej pomocy. Jedyne, co może zrobić, to przetłumaczyć dane wyrażenie LINQ na kryteria NHibernate.

W każdym razie, to jest historia. Chciałbym podkreślić, że strona klienta w ogóle nie jest świadoma NHibernate i lubię ją pozostać w ten sposób.

P.S.

Używam NH 2.1

Odpowiedz

-3

W repozytorium/dao/persistencemanager/cokolwiek klasa:

public IEnumerable<T> FindAll(DetachedCriteria criteria) 

     { 

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

     } 

a następnie po

public void Delete(DetachedCriteria criteria) 

     { 

      foreach (T entity in FindAll(criteria)) 

      { 

       Delete(entity); 

      } 

     } 

Zobacz Davy Brion Data Access with NHibernate.

Edit:

O ile mi wiadomo, jeśli chcesz stosować kryteria trzeba załadować obiektów i iteracyjne nad nimi, aby je usunąć. Alternatywnie można użyć HQL lub przekazać SQL do sesji.

+6

Nie podoba mi się ta metoda, mimo że pracuję z dużą liczbą obiektów, ponieważ wymaga ona pobrania wszystkich elementów z bazy danych przed ich usunięciem. –

+3

To prawda, nie musisz używać HQL do wydania instrukcji "DELETE FROM WHERE"? – DanB

+2

Faceci, nie mówisz poważnie. Musi istnieć lepszy sposób! – mark

7

Możesz użyć kryteriów, aby wybrać identyfikatory swoich elementów, połączyć je w łańcuch i użyć HQL, aby je usunąć?

Coś jak:

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

Kod ten nie był testowany lub skompilowany (w szczególności nie jestem pewien sekcji HQL), ale myślę, że masz pomysł: nie pobierze całe obiekty dzięki projekcji, ale tylko wskaźniki.

+1

Czy to oznacza dwie wycieczki w obie strony do bazy danych? Jeśli tak, to nie jest wystarczająco dobre, ponieważ natywny SQL to po prostu w jednym. – mark

+1

Nadal lepsze niż N + 1 ... Nie mogę wymyślić lepszy sposób za pomocą kryteriów:/ – madprog

3

Po prostu, do 2.1.2, nie możesz.

Jeśli jednak można przetłumaczyć wyrażenie LINQ na HQL (lub ICriteria na HQL), można użyć przeciążonej metody ISession.Delete(), która wykorzystuje przekazany ciąg HQL.

+0

Wiem, że mogę, ale czy nie wydaje się dziwne, że LINQ do NHibernate tłumaczy LINQ do kryteriów, zamiast do HQL, chociaż ten ostatni ma być silniejszym? Być może to wcale nie jest takie proste. Chciałbym zobaczyć działający prototyp ... – mark

+0

Nie powiedziałbym, że HQL jest silniejszy niż Kryteria, i na odwrót. Są to tylko dwie różne konstrukcje, zwykle o różnych celach: HQL dla jednorazowych specyficznych zapytań i kryteriów dla budowania zapytań, unikając wszystkich problemów związanych z konkatenacją ciągów, modułowej obsługi za pomocą DetachedCriteria i wciąż będąc bliżej twojego mapowania. Konstrukcja przykładowa jest również słodka, ale w rzeczywistości rzadko używana. W każdym razie nie używam LINQ dla nhibernate -yet- więc nie mam żadnych przykładów do podania. Niemniej jednak, aż nowsza wersja obsługuje to, co chcesz, Kryteria są tylko dla oświadczeń wybranych – Jaguar

-5

Wiem, że to stare pytanie, ale z powodu kłótni; jeśli ktoś używa repozytorium wzór można zadeklarować usuwania metodę, która wykonuje następujące operacje:

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

Uwaga kod jest przy użyciu wyrażeń w celu interfejsu repozytorium być wystarczająco rodzajowy, więc można też zaimplementować na przykład repozytorium Entity Framework.

+4

Niezupełnie. To, co robisz, to użyj wyrażenia, aby pobrać elementy, a następnie usuń je jeden po drugim. To nie usuwa elementów przez wyrażenie. Mam na myśli posiadanie natywnego API, które otrzymuje wyrażenie, konwertuje je do odpowiedniej instrukcji SQL usuwania, a następnie usuwa wszystkie jednostki za jednym zamachem. – mark

+2

To wymaga dużego ostrzeżenia o tym, jak to nie będzie miłe, gdy masz dużo przedmiotów. –

Powiązane problemy