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