Is it possible for nhibernate to return a query as

2019-06-17 01:47发布

问题:

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?

回答1:

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
}


回答2:

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

something like this?



回答3:

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>.



回答4:

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.



回答5:

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.



回答6:

You can do this by performing a client-side linq projection, see Diego's answer to this post.