2010-09-03 10 views
8

que tener una persona entidad:¿Es posible que nhibernate devuelva una consulta como IDictionary en lugar de una clase de entidad?

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 las asignaciones:

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

Hay algunos stuations donde me gustaría Nhibernate para regresar un diccionario en lugar de la entidad:

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

¿Es esto posible sin agregar un mapeo diferente?

Respuesta

12

Deberá definir su propia implementación de ResultTransformer para que funcione de la manera que lo necesita. A continuación hay una implementación de referencia que puede modificar según sea necesario. Hay una completa falta de comprobación de errores, etc. a fin de utilizar con precaución;)

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

Solución muy limpia. ¡Excelente! –

+0

¿Cómo se usaría esto en la consulta? ¿Puedes mostrar el uso? – emirhosseini

+0

@emirhosseini - el uso sería algo así como: session.CreateSQLQuery ("select p.Name, p.Price, p.ProductId from Product p"). SetResultTransformer (new DictionaryResultTransformer()). List >(); – DanP

0

mirada a esta entrada del blog:

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

Si quieres un ejemplo concreto, comprobar las muestras de este buen tutorial. Mira los resúmenes que no sean entidades y tener la lógica de asignación personalizada:

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

o hacer una búsqueda en Google sobre SetResultTransformer que está disponible sólo para eso, transformar los resultados en otros objetos o colecciones. Incluyendo IDictionnary.

+0

¿Puede proporcionar un ejemplo del uso de un transformador de resultados para poblar un diccionario? No creo que sea posible sin escribir un IResultTransformer personalizado. –

+0

Sí, tienes que escribir el código.Escribir código limpio a veces requiere más esfuerzos. –

1

No, pero puede lograrlo fácilmente encapsulando la lógica en un método de repositorio.

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

También podría utilizar la reflexión para poblar el diccionario.

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

algo como esto?

+0

que está muy cerca de lo que quiero hacer. El problema con eso es que cada hashtable tiene un par de valores clave en donde el objeto de la persona es el valor. Estoy tratando de obtener una tabla hash que tenga cada propiedad como un par de valores clave. – wusher

0

Puede hacerlo realizando una proyección linq del lado del cliente; consulte la respuesta de Diego al this post.

+0

Eso está cerca de lo que estoy tratando de hacer; sin embargo, no creo que sea posible usar proyecciones para crear un KeyValuePair para un nombre de columna y su valor. – wusher

+0

@Maudite: De acuerdo ... Veo a qué se dirige. Déjeme publicar una nueva respuesta con un ejemplo de transformador de resultados impl. – DanP

2

No es necesario que el DictionaryResultTransformerDanP posted.AliasToEntityMapTransformer hace lo mismo, aunque ni va a funcionar por sí solo. Obtendrás un diccionario de entidades.

La única manera que he encontrado para hacerlo es proyectar cada propiedad individualmente. Sin embargo, no desea hacer a mano que porque se romperá cada vez que cambie su asignación. La solución es algo como esto:

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

En el ejemplo anterior, estoy usando una consulta para simular un Get. Por supuesto, puede cambiar esto un poco y devolver una colección; simplemente llame al List<T> en lugar de UniqueResult<T>.

+0

Funciona como un encanto –

Cuestiones relacionadas