我想执行这样的查询,但它失败了:
session.Linq<Product>().Where(p=>p.Id.ToString().StartsWith("123"))
有解决方法吗?我更喜欢使用LINQ ...也许有一种简单的方法来扩展linq提供程序?
我正在使用NHibernate 2.1.2
编辑:是的,它失败了,因为NHIbernate.Linq不处理ToString()
答案 0 :(得分:3)
我同意评论中的SLaks,如果您需要在产品ID字段中进行字符串比较,那么首先应该是char
或varchar
字段。
产品ID中的位数是否恒定?在这种情况下,您可以编写如下内容:
session.Linq<Product>().Where(p=>p.Id >= 10000 && p.Id < 20000)
即使您不知道位数,也可以写
session.Linq<Product>().Where(p=>
(p.Id >= 10 && p.Id < 20) ||
(p.Id >= 100 && p.Id < 200) ||
(p.Id >= 1000 && p.Id < 2000) ||
(p.Id >= 10000 && p.Id < 20000) || ... );
嗯,这很难看,但它会起作用: - )
顺便说一句,您可以使用以下表达式获取T-SQL中的第一个数字:
(Product.Id / POWER(10, FLOOR(LOG10(Product.Id))))
但是,我不认为NHibernate 2.1.2的Linq提供程序能够将.Net数学函数映射到相应的T-SQL函数。你可以尝试一下:
session.Linq<Product>().Where(p => p.Id / Math.Pow(10, Math.Floor(Math.Log10(p.Id))) == 1)
答案 1 :(得分:2)
如果你升级到NHibernate 3,你可以extend the LINQ provider因此它会识别像p.Id.NumberStartsWith(1)
这样的表达式(这将包含建议作为这个问题的答案的任何方法)
这是一点点的工作,但一旦完成,客户端代码看起来会很不错。
另外,你会有很多乐趣: - )
答案 2 :(得分:1)
查询可能会失败,因为NHibernate不知道如何将ToString()(或各种解析)转换为CAST / CONVERT方法。
我同意Elian和SLaks - 如果您需要产品ID中的单个“字符”,则此ID应为varchar。没有真正优雅的方式让这个查询工作;如果它是一个字符串,StartsWith()函数将被转换为ProductId LIKE 'x%'
条件,并没有那么大惊小怪。
答案 3 :(得分:1)
如果您绝对需要这样做,您可能想要做的是创建一个可能是您的密钥的字符串版本的并行列。使用NHibernate拦截器,数据库触发器或许多其他选项可以保持字段更新和同步,而不会使代码混乱。
我想我会避免这样做,但这是你可以采取的一种方式。