NHibernate:如何使用CreateSQLQuery返回标量值列表(从一列)?

时间:2018-07-16 14:28:42

标签: c# .net nhibernate

调用原生SQL返回具有ISession对象的标量值列表(在我的情况下为int)的最佳/最干净方法是什么?

我正在尝试运行以下命令,但总是出现一些错误:

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的int属性的实体类的情况下检索int列表的方法?

2 个答案:

答案 0 :(得分:1)

当您从List调用CreateSQLQuery时,您将获得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范围上的映射表,则可以使用LINQ进行此操作,例如:

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

答案 1 :(得分:1)

我知道您没有使用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是表示(映射到)表的实体。请注意,这只是建立查询。它不会返回实体。

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

IProjection column参数是您要选择的列的名称。

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查询作为字符串编写。如您所见,此函数可以与任何实体(表)和任何列一起使用。