Raccolta di filtri NHibernate
-
07-07-2019 - |
Domanda
Utilizzando NHibernate, voglio filtrare una raccolta in una classe per contenere SOLO un sottoinsieme di possibili oggetti. Di seguito includo i dati di una tabella di esempio per spiegare. Non riesco a trovare alcun modo per farlo utilizzando NHibernate.
Tabella: DataObject
DataObjectId (PK) / Name / CurrentVersion
11 "data.txt" 2
12 "info.txt" 3
Tabella: DataObjectVersion
Id / Comment / VersionNumber / DataObjectId (FK)
31 "Genesis" 1 11 <= Ignore this object
32 "Changed data" 2 11 <= Get this object
34 "Genesis" 1 12 <= Ignore this object
35 "Changed info" 2 12 <= Ignore this object
36 "Added info" 3 12 <= Get this object
Voglio unirmi a una chiave non esterna DataObject.CurrentVersion = DataObjectVersion.VersionNumber per ciascun DataObject in un comando.
Ecco le classi e i file di mappatura:
public class DataObject
{
public virtual int DataObjectId { get; set; }
public virtual string Name { get; set; }
public virtual int CurrentVersionNumber { get; set; }
public virtual IList<DataObjectVersion> Versions { get; set; }
}
<class name="DataObject" table="DataObject" lazy="false">
<id name="DataObjectId" column="DataObjectId" type="int">
<generator class="assigned" />
</id>
<property name="Name" column="Name" type="String(512)" />
<property name="CurrentVersionNumber" column="CurrentVersionNumber" type="int" />
<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" >
<key column="DataObjectId" />
<one-to-many class="DataObjectVersion" />
</bag>
</class>
public class DataObjectVersion
{
public virtual int DataObjectVersionId { get; set; }
public virtual string Comment { get; set; }
public virtual int VersionNumber { get; set; }
public virtual int DataObjectId { get; set; }
}
<class name="DataObjectVersion" table="DataObjectVersion" lazy="false">
<id name="Id" column="DataObjectVersionId" type="int">
<generator class="assigned" />
</id>
<property name="Comment" column="Comment" type="String(512)" />
<property name="VersionNumber" column="VersionNumber" type="int" />
<property name="DataObjectId" column="DataObjectId" type="int" />
</class>
Soluzione
se si desidera filtrare la raccolta su richiesta, utilizzare un filtro è una scelta valida. Dovresti dichiarare il filtro sia sulla classe Version che nell'elemento bag e applicare il filtro dal metodo NHibernateSession.EnableFilter
se vuoi sempre recuperare una singola versione nella borsa, implementa un 'dove' nella mappatura della borsa:
<bag name="Versions" cascade="all-delete-orphan" inverse="true" lazy="false" where="CurrentVersionNumber = Versions.VersionNumber" >
<key column="DataObjectId" />
<one-to-many class="DataObjectVersion" />
</bag>
nota che nel 'dove' scrivi l'SQL corretto non l'HQL e come tale l'SQL corretto che scrivo sopra probabilmente deve essere cambiato per riflettere il tuo schema
Inoltre, se un singolo oggetto deve essere recuperato impostando un sacchetto e l'IList corrispondente può essere un eccessivo. L'applicazione di una proprietà formula e un oggetto DataObjectVersion nella classe potrebbe essere più appropriata
nella classe DataObject sostituisce IList con
public virtual DataObjectVersion Version { get; set; }
e nella mappatura sostituisci la 'borsa' con qualcosa nelle righe di
<property name="Version" type="DataObjectVersion" update="false" insert="false" formula="(select v.DataObjectVersionId, v.Comments, v.VersionNumber, v.DataObjectId from DataObjectVersion v where v.VersionNumber = CurrentVersionNumber)" />
di nuovo è consentito solo l'SQL corretto
ho usato proprietà calcolate con tipi di dati nativi (data / ora, stringa ecc.) e il recupero di un'entità può (o non può) aver bisogno di qualcosa di più o di diverso
Ultimo ma non meno importante, è possibile applicare un filtro sulla raccolta dopo dopo aver recuperato l'oggetto primario DataObject creando un filtro sulla raccolta
IList<DataObjectVersion> fVersion =
NHibernateSession.CreateFilter(do.Versions, "where VersionNumber = :ver")
.SetParameter("ver", do.CurrentVersionNumber)
.List<DataObjectVersion>();
dove la raccolta do.Versions non è inizializzata, vengono recuperati solo i risultati nella raccolta fVersion separata e questa è una seconda SELEZIONE dopo aver già effettuato il round trip per il db per il recupero di DataObject.
Altri suggerimenti
Presumibilmente il tuo VersionNumber aumenta man mano che l'utente modifica i dati e stai cercando di ottenere quello più recente. Se consideri il VersionNumber come un " Età " invece campo (ovvero dove 0 è la versione più recente / più recente, 1 è la versione più vecchia successiva e così via), i tuoi problemi diventano come ottenere tutte le entità con un'età di 0. Questo può essere fatto usando un filtro: http://nhibernate.info/doc/nh/en/index.html#objectstate- filtri