I have an entity Person:
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; }
}
with the mappings:
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();
}
}
There are some stuations where I would like Nhibernate to return a dictionary instead of the entity:
IDictionary<string,string> person = session.Get(id);//????
string firstName = person["FirstName"];
Is this possible to without adding a different mapping?
You will need to define your own ResultTransformer implementation to have this working the way you need it. Below is a reference implementation that you can tweak as needed. There is a complete lack of error-checking, etc; so use with caution ;)
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
}
session.CreateCriteria<Person>()
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToEntityMap)
.List<Hashtable>();
something like this?
You don't need the DictionaryResultTransformer
that DanP posted. AliasToEntityMapTransformer
does the same thing, though neither will work on its own. You'll get a dictionary of entities.
The only way I have found to do it is to project each property individually. However you don't want to do that by hand because it will break whenever you change your mapping. The solution is something like this:
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>()
In the above example, I am using a query to simulate a Get
. Of course, you can change this a bit and return a collection instead; just call List<T>
instead of UniqueResult<T>
.
No, but you can easily accomplish that by encapsulating the logic in a repository method.
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;
}
You could also use reflection to populate the dictionary.
Look at this blog post:
http://sdesmedt.wordpress.com/2006/09/04/nhibernate-part-4-mapping-techniques-for-aggregation-one-to-many-mapping/
If you want a concrete example, check the samples of this nice tutorial. Look at the summaries that are not entities and have custom mapping logic:
http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx
Or do a google search on SetResultTransformer that is available just for that, transform results in another objects or collections. Including IDictionnary.
You can do this by performing a client-side linq projection, see Diego's answer to this post.