NHibernate:如何使用 CreateSQLQuery return 标量值列表(来自一列)?

NHibernate: How to return list of scalar values (from one column) using CreateSQLQuery?

调用本机 SQL 返回具有 ISession 对象的标量值列表(在我的例子中是整数)的 best/cleanest 方法是什么?

我正在尝试 运行 以下内容,但我总是遇到一些错误:

var query = _session.CreateSQLQuery("SELECT Id FROM SomeTable");

A. var ids = query.List<int>(); // <-- throws ArgumentNullException "Value cannot be null.\r\nParameter name: item"
B. var ids = query.List(); returns one element array with no valid information.
C. query.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean<int>());
var ids = query.List<int>(); // throws PropertyNotFoundException: "Could not find a setter for property 'Id' in class 'System.Int32'"

有没有一种方法可以在不创建仅包含一个名为 Id 属性 的整数的实体 class 的情况下检索整数列表?

当您从 CreateSQLQuery 调用 List 时,您将获得 IList 的一个实例,它在内部是一个 List<object>。如果此结果有空值,则无法转换为 int,因为它是值类型。因此,一个解决方案是迭代结果并在它是有效整数时将其转换。例如:

var values = _session.CreateSQLQuery("SELECT Id FROM SomeTable").List();
var ids = new List<int>();

foreach (var item in values)
{
   if (item != null)
      ids.Add(Convert.ToInt32(item));
}

如果这是 nhibernate 作用域上的映射 table,您可以使用 LINQ 来执行此操作,例如:

var ids = session.Query<SomeEntity>().Select(x => x.Id).ToList();

我知道您没有使用 IQueryOver,但它比您现在使用的方法更简单、更动态、更清晰。

public IList<TReturn> GetValues<TEntity, TReturn>(IProjection column, Junction where, int top) where TEntity : BaseEntity
{
    IQueryOver<TEntity> query = null;
    if(where == null)
        query = session.QueryOver<TEntity>().Select(column);
    else
        query = session.QueryOver<TEntity>().Select(column).Where(where);

    IList<TReturn> instance = null;
    if(top == 0)
        instance = query.List<TReturn>();
    else
        instance = query.Take(top).List<TReturn>();
    return instance;
}
上面代码中的

TEntity 是代表(映射到)您的 table 的实体。请注意,这只是为了构建查询。它不会 return 实体。

TReturn 是 return 类型。在您的情况下,这可以是任何标准数据类型,例如 int

IProjection column参数是你要select的列名。

Junction where 参数允许您在行上指定过滤器(如果有)。要检索所有行,请将其传递 null.

以下是您对它的称呼:

Junction where = Restrictions.Conjunction();
where.Add(Restrictions.Eq(..........));

IList<int> idList = GetValues<SomeTableEntity, int>(Projections.Property<SomeTableEntity>(x => x.Id), where, 0);

这样,您就可以避免在代码中将硬编码 SQL 查询作为字符串编写。如您所见,此函数可用于任何实体 (table) 和任何列。