2010-09-03 11 views
8

Mam Osoba:Czy nhibernate może zwrócić zapytanie jako IDictionary zamiast klasy entity?

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

z odwzorowań:

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

Istnieją pewne stuations których chciałbym Nhibernate wrócić słownika zamiast podmiotu:

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

Czy można to zrobić bez dodawania innego odwzorowania?

Odpowiedz

12

Będziesz musiał zdefiniować własną implementację ResultTransformer, aby działała tak, jak tego potrzebujesz. Poniżej znajduje się implementacja referencyjna, którą można dostosować w razie potrzeby. Istnieje kompletny brak sprawdzania błędów itp .; więc używać z ostrożnością;)

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

Bardzo czyste rozwiązanie. Doskonały! –

+0

W jaki sposób zostanie to użyte w zapytaniu? Czy możesz pokazać użycie? – emirhosseini

+0

@emirhosseini - użycie byłoby coś w stylu: session.CreateSQLQuery ("select p.Name, p.Price, p.ProductId z Product p") SetResultTransformer (new DictionaryResultTransformer()). Lista >(); – DanP

0

Spójrz na tym blogu:

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

Jeśli chcesz konkretny przykład, sprawdzić próbki tego ładnym kursie. Spójrz na podsumowania, które nie są żywe i mają niestandardową logikę mapowania:

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

Albo zrobić wyszukiwania Google na SetResultTransformer, który jest dostępny tylko dla tego, przekształcanie wyników w kolejnych obiektów lub kolekcji. W tym IDictionnary.

+0

Czy możesz podać przykład użycia transformatora wyników do wypełnienia słownika? Nie sądzę, że jest to możliwe bez napisania niestandardowego narzędzia IResultTransformer. –

+0

Tak, musisz napisać kod.Pisanie czystego kodu czasami wymaga więcej wysiłku. –

1

Nie, ale można to łatwo osiągnąć poprzez enkapsulację logiki w metodzie repozytorium.

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

Można również użyć odbicia, aby wypełnić słownik.

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

coś takiego?

+0

który jest bardzo zbliżony do tego, co chcę zrobić. Problem polega na tym, że każdy obiekt hashtable ma jedną parę kluczy, w której obiekt osoby jest wartością. Próbuję uzyskać hashtable, który ma każdą właściwość jako parę wartości klucza. – wusher

0

Możesz to zrobić, wykonując projekcję linq po stronie klienta, zobacz odpowiedź Diego na this post.

+0

To jest blisko tego, co próbuję zrobić; nie sądzę jednak, aby można było użyć prognoz do utworzenia KeyValuePair dla nazwy kolumny i jej wartości. – wusher

+0

@Maudite: Dobra. Widzę, do czego zmierzasz. Opowiedz mi o nowej odpowiedzi z przykładowym transformatorem wynikowym impl. – DanP

2

Nie potrzebne DictionaryResultTransformer że DanP posted.AliasToEntityMapTransformer robi to samo, ale nie będzie działać na własną rękę. Dostaniesz słownik bytów.

Jedynym sposobem, jaki udało mi się to zrobić, jest indywidualne zaprojektowanie każdej nieruchomości. Jednak nie chcesz robić tego ręcznie, ponieważ ulegnie to uszkodzeniu po każdej zmianie mapowania. Rozwiązaniem jest coś takiego:

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>() 

W powyższym przykładzie, używam kwerendę do symulowania Get. Oczywiście możesz zmienić to nieco i zamiast tego zwrócić kolekcję; wystarczy zadzwonić pod numer List<T> zamiast UniqueResult<T>.

+0

Działa jak urok –

Powiązane problemy