我们在decimal(20,5)类型的数据库中有一个货币字段。 如何将CAST或COnvert添加到传出的Nhibernate标准?
SELECT
TOP (1000) this_.DepositAccountId as DepositA1_71_0_,
this_.BranchId as BranchId71_0_,
this_.ConfigurationStatusId as Configu14_71_0_,
this_.ConfiguredBy as Configu41_71_0_,
this_.ConfiguredDate as Configu15_71_0_,
this_.DepositAccountBalance as DepositA9_71_0_
FROM
dbo.DepositAccount this_
WHERE
Convert(Decimal(20,2), this_.DepositAccountBalance) = 1.01
目前它像这样发送WHERE子句
WHERE
this_.DepositAccountBalance = 1.01
我需要添加转换或转换或舍入。
数据库中有一条记录,其中DepositAccountBalance = 1.0107。 因此,如果没有Cast或Convert,则没有匹配项。
网站上有一些资源可供人们添加精度,缩放到生成的.hbm.xml。其中一些人建议使用Nhibernate Dialect和自定义SQL函数
有谁可以解释我需要哪一个?我什么时候使用Nhibernate Dialect。我何时将精度添加到.hbm.xml。我需要做的就是在where子句
中添加Convert或round答案 0 :(得分:2)
所以 应该工作(我已经大大简化了查询,但问题都是一样的):
IType decimalType = TypeFactory.Basic("decimal(20,2)");
IProjection castProjection = Projections.Cast(
decimalType,
Projections.Property<DepositAccount>(acct => acct.DepositAccountBalance));
var accounts = session.QueryOver<DepositAccount>()
.Where(Restrictions.Eq(castProjection, 1.01))
.List<DepositAccount>();
不幸的是,这会生成以下SQL:
SELECT
this_.*
FROM
DepositAccount this_
WHERE
cast( this_.DepositAccountBalance as DECIMAL(19,5)) = 1.01
咦?我们刚刚指定我们想要一个类型decimal(20,2)
!发生了什么事?
看起来CastProjection
完全忽略了传递它的类型的精度和比例。这是CastProjection
类的相关代码:
public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
{
ISessionFactoryImplementor factory = criteriaQuery.Factory;
SqlType[] sqlTypeCodes = type.SqlTypes(factory);
if (sqlTypeCodes.Length != 1)
{
throw new QueryException("invalid Hibernate type for CastProjection");
}
// HERE: precision and scale are being ignored.
string sqlType = factory.Dialect.GetCastTypeName(sqlTypeCodes[0]);
int loc = position*GetHashCode();
SqlString val = projection.ToSqlString(criteria, loc, criteriaQuery,enabledFilters);
val = SqlStringHelper.RemoveAsAliasesFromSql(val);
return new SqlString("cast( ", val, " as ", sqlType, ") as ", GetColumnAliases(position, criteria, criteriaQuery)[0]);
}
对于所有GetCastTypeName
类型,decimal(19,5)
只返回decimal
,这似乎是一个错误。
有两种方法可以解决这个问题:
使用Projections.SqlFunction
(推荐 - 不知道#2的后果是什么)
要做到这一点,我们只需要使用Projections.SqlFunction
明确为我们执行cast
:
var decimalType = TypeFactory.Basic("decimal(20,2)");
var castProjection = Projections.SqlFunction(
new SQLFunctionTemplate(decimalType, "cast(?1 as decimal(20,2))"),
decimalType,
Projections.Property<DepositAccount>(acct=> acct.DepositAccountBalance));
var q = session.QueryOver<DepositAccount>()
.Where(Restrictions.Eq(castProjection, 1.01))
.List<DepositAccount>();
这会生成预期的SQL:
SELECT
this_.*
FROM
DepositAccount this_
WHERE
cast(this_.DepositAccountBalance as decimal(20,2)) = 1.01
编写我们自己的类来正确进行强制转换。我们实际上只需要更改一行代码就可以使其工作。否则它与CastProjection
类完全相同:
public class PrecisionCast : SimpleProjection
{
private readonly IType type;
private readonly IProjection projection;
public PrecisionCast(IType type, IProjection projection)
{
this.type = type;
this.projection = projection;
}
public override bool IsAggregate
{
get { return false; }
}
public override SqlString ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
{
ISessionFactoryImplementor factory = criteriaQuery.Factory;
SqlType[] sqlTypeCodes = type.SqlTypes(factory);
if (sqlTypeCodes.Length != 1)
{
throw new QueryException("invalid Hibernate type for CastProjection");
}
// Get the type name, preserving scale and precision
string sqlType = factory.Dialect.GetTypeName(sqlTypeCodes[0]);
int loc = position*GetHashCode();
SqlString val = projection.ToSqlString(criteria, loc, criteriaQuery,enabledFilters);
val = SqlStringHelper.RemoveAsAliasesFromSql(val);
return new SqlString("cast( ", val, " as ", sqlType, ") as ", GetColumnAliases(position, criteria, criteriaQuery)[0]);
}
public override IType[] GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return new IType[]{ type };
}
public override NHibernate.Engine.TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
{
return projection.GetTypedValues(criteria, criteriaQuery);
}
public override bool IsGrouped
{
get
{
return projection.IsGrouped;
}
}
public override SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary<string, IFilter> enabledFilters)
{
return projection.ToGroupSqlString(criteria, criteriaQuery, enabledFilters);
}
}
然后像这样使用它:
var decimalType = TypeFactory.Basic("decimal(20,2)");
var castProjection = new PrecisionCast(
decimalType, Projections.Property<DepositAccount>(acct => acct.DepositAccountBalance));
var accounts = session.QueryOver<DepositAccount>()
.Where(Restrictions.Eq(castProjection, 1.01))
.List<DepositAccount>();
这似乎解决了decimal
类型的问题,但我不知道其他类型的后果是什么,因此不保证此代码。
希望这会有所帮助。我和#1一起去。