2010-09-03 17 views
8

ho avere una persona un'entità:E 'possibile che nhibernate restituisca una query come IDictionary invece di una classe di entità?

public class Person 
{ 
    public virtual int Id {get; set; } 
    public virtual string FirstName { get; set; } 
    public virtual string MiddleName { get; set; } 
    public virtual string LastName { get; set; } 
} 

con le mappature:

public class PersonMap 
{ 
    public PersonMap() 
    { 
     Table(TABLE_NAME); 
     Id(x => x.Id); 
     Map(x => x.FirstName).Not.Nullable(); 
     Map(x => x.LastName).Not.Nullable(); 
     Map(x => x.MiddleName).Not.Nullable(); 
    } 
} 

Ci sono alcune stuations dove vorrei NHibernate per restituire un dizionario al posto del soggetto:

IDictionary<string,string> person = session.Get(id);//???? 
string firstName = person["FirstName"]; 

E 'possibile senza aggiungere una mappatura diversa?

risposta

12

Sarà necessario definire la propria implementazione ResultTransformer per far sì che funzioni nel modo desiderato. Di seguito è riportata un'implementazione di riferimento che è possibile modificare secondo necessità. C'è una completa mancanza di controllo degli errori, ecc; in modo da utilizzare con cautela;)

using System; 
using System.Collections; 
using NHibernate; 
using NHibernate.Properties; 
using NHibernate.Transform; 


[Serializable] 
public class DictionaryResultTransformer : IResultTransformer 
{ 

     public DictionaryResultTransformer() 
     { 

     } 

     #region IResultTransformer Members 

     public IList TransformList(IList collection) 
     { 
       return collection; 
     } 

     public object TransformTuple(object[] tuple, string[] aliases) 
     { 
      var result = new Dictionary<string,object>(); 
      for (int i = 0; i < aliases.Length; i++) 
      { 
      result[aliases[i]] = tuple[i];       
      } 
      return result; 
     } 

     #endregion 
} 
+0

Soluzione molto pulita. Eccellente! –

+0

Come verrebbe utilizzato dalla query? Puoi mostrare l'utilizzo? – emirhosseini

+0

@emirhosseini: l'utilizzo è simile a: session.CreateSQLQuery ("seleziona p.Nome, p.Prezzo, p.ProductId da Prodotto p"). SetResultTransformer (nuovo DictionaryResultTransformer()). Elenco >(); – DanP

0

un'occhiata a questo post del blog:

http://sdesmedt.wordpress.com/2006/09/04/nhibernate-part-4-mapping-techniques-for-aggregation-one-to-many-mapping/

Se volete un esempio concreto, controllare i campioni di questo bel tutorial. Guarda le sintesi che non sono entità e hanno logica mappatura personalizzata:

http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx

o fare una ricerca su google SetResultTransformer che è disponibile solo per questo, trasformare i risultati in un altro oggetti o collezioni. Compreso IDictionnary.

+0

Potete fornire un esempio di utilizzo di un trasformatore di risultati per popolare un dizionario? Non penso sia possibile senza scrivere un IResultTransformer personalizzato. –

+0

Sì, devi scrivere codice.Scrivere codice pulito a volte richiede più sforzi. –

1

No, ma è possibile farlo facilmente incapsulando la logica in un metodo di repository.

public IDictionary<string, string> GetPersonDictionary(int id) 
{ 
    var person = session.Get<Person>(id); 
    var dict = new Dictionary<string, string>(); 
    dict.Add("FirstName", person.FirstName); 
    /// etc. 
    return dict; 
} 

È anche possibile utilizzare la riflessione per popolare il dizionario.

2
session.CreateCriteria<Person>() 
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToEntityMap) 
.List<Hashtable>(); 

qualcosa del genere?

+0

che è molto vicino a quello che voglio fare. Il problema è che ogni hashtable ha una coppia di valori chiave in cui l'oggetto person è il valore. Sto cercando di ottenere una tabella hash che ha ciascuna proprietà come coppia di valori chiave. – wusher

0

È possibile eseguire questa operazione eseguendo una proiezione linq lato client, vedere la risposta di Diego a this post.

+0

Questo è vicino a quello che sto cercando di fare; tuttavia, non penso sia possibile utilizzare le proiezioni per creare un KeyValuePair per il nome di una colonna e il suo valore. – wusher

+0

@Maudite: Bene..Vedo cosa stai ottenendo..mi posta una nuova risposta con un esempio di trasformatore di risultati impl. – DanP

2

Non è necessario il DictionaryResultTransformer che DanP posted.AliasToEntityMapTransformer fa la stessa cosa, anche se nessuno lavorerà da solo. Otterrai un dizionario di entità.

L'unico modo che ho trovato di fare è proiettare ciascuna proprietà individualmente. Comunque non vuoi fare che a mano perché si romperà ogni volta che cambierai la mappatura. La soluzione è qualcosa di simile:

var criteria = DetachedCriteria.For<Person>(); 
criteria.Add(Restrictions.Eq("Id", id)); 
var projectionList = Projections.ProjectionList(); 
var metadata = session.SessionFactory.GetClassMetadata(typeof(Person)); 
foreach (var name in metadata.PropertyNames) 
{ 
    projectionList.Add(Projections.Property(name), name); 
} 
criteria 
    .SetProjection(projectionList) 
    .SetResultTransformer(Transformers.AliasToEntityMap); 
var result = criteria.GetExecutableCriteria(session) 
    .UniqueResult<IDictionary>() 

Nell'esempio di cui sopra, sto usando una query per simulare un Get. Certo, puoi cambiarlo un po 'e restituire una collezione; basta chiamare List<T> anziché UniqueResult<T>.

+0

Funziona come un fascino –

Problemi correlati