nhibernate能否返回一个IDictionary而不是实体类作为查询结果?

8

我有一个实体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; }
}

使用以下映射:

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

有些情况下,我希望NHibernate返回字典而不是实体对象:
IDictionary<string,string> person = session.Get(id);//????
string firstName = person["FirstName"];

不添加其他映射,是否可能实现这个功能?

6个回答

13

您需要定义自己的ResultTransformer实现才能使其按照您的需求工作。下面是一个参考实现,您可以根据需要进行调整。缺乏完整的错误检查等内容,请小心使用;)

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
}

非常干净的解决方案。太棒了! - João Passos
这个查询如何使用?你能展示一下用法吗? - emirhosseini
@emirhosseini - 用法类似于:session.CreateSQLQuery("select p.Name, p.Price, p.ProductId from Product p").SetResultTransformer(new DictionaryResultTransformer()).List<Dictionary<string,object>>(); - DanP

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

像这样的内容吗?


那非常接近我想要做的事情。问题在于每个哈希表中只有一个键值对,其中人物对象是值。我正在尝试获取一个将每个属性作为键值对的哈希表。 - wusher

2
您不需要像DanP发表的那样使用DictionaryResultTransformer。虽然AliasToEntityMapTransformer也可以实现相同的功能,但是它们都不能单独使用。您将获得一个实体字典。
我发现唯一的方法是逐个投影每个属性。但是您不想手动执行此操作,因为它会在更改映射时出错。解决方案类似于这样:
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>()

在上面的例子中,我使用了一个查询来模拟一个 Get 操作。当然,你可以稍微修改一下,返回一个集合;只需要调用 List<T> 而不是 UniqueResult<T> 即可。

1
不可以,但是你可以通过将逻辑封装在存储库方法中轻松实现。
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;
}

你也可以使用反射来填充字典。


0

你能提供一个使用结果转换器填充字典的例子吗?我认为如果不编写自定义 IResultTransformer 的话是不可能的。 - Jamie Ide
是的,你必须编写代码。编写干净的代码有时需要更多的努力。 - user333306

0

您可以通过执行客户端 Linq 投影来实现此操作,请参见 Diego 在 this post 中的答案。


这接近我所尝试的目标;然而,我不认为可以使用投影来创建一个列名称和其值的KeyValuePair。 - wusher
@Maudite:好的,我明白你的意思了。让我发布一个新答案,附带一个示例结果转换器实现。 - DanP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接