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>  
È stato utile?

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top