在 .Any() LINQ 查询中将 'string' 转换为 'int'
Convert 'string' to 'int' in an .Any() LINQ query
我有一个条件语句来评估针对我的数据库的 .Any()
LINQ 查询。
当 casting/converting 一个字符串为 long 值时抛出错误。
(long.TryParse(m.Reference,out t)? t : long.MaxValue)
错误类似于:
LINQ to Entities does not recognize the method '....' method, and this method cannot be translated into a store expression
我是不是做错了什么?我怎样才能做到这一点?
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& item.ShoppingCartWebId > (long.TryParse(m.Reference,out t)? t : long.MaxValue)))
)){
// do something special
}
}
长度检查与 string.Compare 的组合应该可以解决问题。
逻辑
- 如果item.Reference.Length长度更长,它也是一个更大的数字。
- 如果它们的长度相同,则执行
string.Compare
从左到右求值,这也适用于数字。
string.Compare(string a, string b)
。这个returns:
- 1 如果
a
大于 b
- 0 如果
a
等于 b
- -1 如果
b
大于 a
代码:
using (var ctx = new DatabaseEntities())
{
var webId = item.ShoppingCartWebId.ToString();
var webIdLength = webId.Length;
if (!ctx.CustomerInboxes.Any(m => m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& (m.Reference.Length > webIdLength || (m.Reference.Length == webIdLength && string.Compare(m.Reference, webId) > 0))))) {
//do something special
}
}
好处
索引!因为这里不涉及填充,所以实际的比较检查仍然可以受益于在该列上使用任何索引。如果您的数据增长,它不应该对性能产生太大影响。不幸的是,长度比较不会使用我认为的任何索引,但是比较 可能 比查询的其他部分
对性能的影响更小
假设
- 没有
,
或 .
等格式字符
- 没有使用
0
或空格 填充字符串的情况
- 你总是在比较整数(没有分数)
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.ToList().Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& item.ShoppingCartWebId > (long.TryParse(m.Reference,out t)? t : long.MaxValue)))
))
{
// do something special
}
}
只需添加 .ToList()
。虽然这会将您的整个列表返回给客户端,但它允许您执行您想要执行的自定义操作符。
根据此处的评论,另一种方法是从数据库中取回一个子集,然后执行自定义解析运算符。
long t;
var initialQuery = ctx.CustomerInboxes.Where(x => m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage).ToList();
if (!initialQuery.Any(m => item.ShoppingCartWebId > (long.TryParse(m.Reference, out t) ? t : long.MaxValue)))
{
// do something special
}
一个可能的解决方案是在 CustomerInboxes
source table 中添加一个计算列(我假设它是一个 table,但它可以是一个视图或一个存储过程),这样您就不必进行 LINQ2SQL 无法翻译的丑陋比较:
ReferenceAsLong AS ISNULL(TRY_CONVERT(BIGINT, Reference), CAST(9223372036854775807 AS BIGINT)) PERSISTED
令您烦恼的 LINQ 条件已得到简化并且应该可以正常工作:
item.ShoppingCartWebId > ReferenceAsLong
您可以尝试使用 Convert.ToInt64 而不是 long.TryParse。
根据您的代码,当 m.Reference
不是有效数字时,条件应该失败,这可以使用 SqlFunctions.IsNumeric()
来完成。
要比较数字,您可以使用 string.Compare
并用 0
s 模拟数字比较填充(可以用 SqlFunctions.Replicate()
)。
不太漂亮,但应该可以:
var itemId = item.ShoppingCartWebId.ToString();
ctx.CustomerInboxes.Any(m => ...
&& SqlFunctions.IsNumeric(m.Reference) != 0
&& string.Compare(SqlFunctions.Replicate("0", m.Reference.Length > itemId.Length ? m.Reference.Length - itemId.Length : 0) + itemId, m.Reference) > 0);
但是您总是可以切换到 Linq to Objects 来检查这个特定部分:
ctx.CustomerInboxes.Where(m => m.CustomerId == customerId &&
m.Reference == item.ShoppingCartWebId.ToString() &&
m.SubjectId == HerdbookConstants.PendingCartMessage)
.AsEnumerable()
.Any(c => item.ShoppingCartWebId > (long.TryParse(c.Reference, out t) ? t : long.MaxValue))
这个查询看起来会很糟糕。理想情况下,您应该在数据库中将其切换为一个 int 字段。
(只要没有前置的 0)
您可以修改逻辑,以便如果 ShoppingCartWebId 的长度长于满足条件,或者如果长度相等,则字符串比较应该可以正常工作
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& (item.ShoppingCartWebId.length > SqlFunctions.StringConvert((long).Reference)
|| (item.ShoppingCartWebId.length == SqlFunctions.StringConvert((long).Reference
&& item.ShoppingCartWebId > SqlFunctions.StringConvert((long)m.Reference)
))){
//do something special
}
}
我有一个条件语句来评估针对我的数据库的 .Any()
LINQ 查询。
当 casting/converting 一个字符串为 long 值时抛出错误。
(long.TryParse(m.Reference,out t)? t : long.MaxValue)
错误类似于:
LINQ to Entities does not recognize the method '....' method, and this method cannot be translated into a store expression
我是不是做错了什么?我怎样才能做到这一点?
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& item.ShoppingCartWebId > (long.TryParse(m.Reference,out t)? t : long.MaxValue)))
)){
// do something special
}
}
长度检查与 string.Compare 的组合应该可以解决问题。
逻辑
- 如果item.Reference.Length长度更长,它也是一个更大的数字。
- 如果它们的长度相同,则执行
string.Compare
从左到右求值,这也适用于数字。
string.Compare(string a, string b)
。这个returns:
- 1 如果
a
大于b
- 0 如果
a
等于b
- -1 如果
b
大于a
代码:
using (var ctx = new DatabaseEntities())
{
var webId = item.ShoppingCartWebId.ToString();
var webIdLength = webId.Length;
if (!ctx.CustomerInboxes.Any(m => m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& (m.Reference.Length > webIdLength || (m.Reference.Length == webIdLength && string.Compare(m.Reference, webId) > 0))))) {
//do something special
}
}
好处
索引!因为这里不涉及填充,所以实际的比较检查仍然可以受益于在该列上使用任何索引。如果您的数据增长,它不应该对性能产生太大影响。不幸的是,长度比较不会使用我认为的任何索引,但是比较 可能 比查询的其他部分
对性能的影响更小假设
- 没有
,
或.
等格式字符
- 没有使用
0
或空格 填充字符串的情况
- 你总是在比较整数(没有分数)
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.ToList().Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& item.ShoppingCartWebId > (long.TryParse(m.Reference,out t)? t : long.MaxValue)))
))
{
// do something special
}
}
只需添加 .ToList()
。虽然这会将您的整个列表返回给客户端,但它允许您执行您想要执行的自定义操作符。
根据此处的评论,另一种方法是从数据库中取回一个子集,然后执行自定义解析运算符。
long t;
var initialQuery = ctx.CustomerInboxes.Where(x => m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage).ToList();
if (!initialQuery.Any(m => item.ShoppingCartWebId > (long.TryParse(m.Reference, out t) ? t : long.MaxValue)))
{
// do something special
}
一个可能的解决方案是在 CustomerInboxes
source table 中添加一个计算列(我假设它是一个 table,但它可以是一个视图或一个存储过程),这样您就不必进行 LINQ2SQL 无法翻译的丑陋比较:
ReferenceAsLong AS ISNULL(TRY_CONVERT(BIGINT, Reference), CAST(9223372036854775807 AS BIGINT)) PERSISTED
令您烦恼的 LINQ 条件已得到简化并且应该可以正常工作:
item.ShoppingCartWebId > ReferenceAsLong
您可以尝试使用 Convert.ToInt64 而不是 long.TryParse。
根据您的代码,当 m.Reference
不是有效数字时,条件应该失败,这可以使用 SqlFunctions.IsNumeric()
来完成。
要比较数字,您可以使用 string.Compare
并用 0
s 模拟数字比较填充(可以用 SqlFunctions.Replicate()
)。
不太漂亮,但应该可以:
var itemId = item.ShoppingCartWebId.ToString();
ctx.CustomerInboxes.Any(m => ...
&& SqlFunctions.IsNumeric(m.Reference) != 0
&& string.Compare(SqlFunctions.Replicate("0", m.Reference.Length > itemId.Length ? m.Reference.Length - itemId.Length : 0) + itemId, m.Reference) > 0);
但是您总是可以切换到 Linq to Objects 来检查这个特定部分:
ctx.CustomerInboxes.Where(m => m.CustomerId == customerId &&
m.Reference == item.ShoppingCartWebId.ToString() &&
m.SubjectId == HerdbookConstants.PendingCartMessage)
.AsEnumerable()
.Any(c => item.ShoppingCartWebId > (long.TryParse(c.Reference, out t) ? t : long.MaxValue))
这个查询看起来会很糟糕。理想情况下,您应该在数据库中将其切换为一个 int 字段。
(只要没有前置的 0)
您可以修改逻辑,以便如果 ShoppingCartWebId 的长度长于满足条件,或者如果长度相等,则字符串比较应该可以正常工作
using (var ctx = new DatabaseEntities())
{
long t;
if(!ctx.CustomerInboxes.Any(m=>m.CustomerId == customerId
&& m.Reference == item.ShoppingCartWebId.ToString()
&& m.SubjectId == HerdbookConstants.PendingCartMessage
&& (item.ShoppingCartWebId.length > SqlFunctions.StringConvert((long).Reference)
|| (item.ShoppingCartWebId.length == SqlFunctions.StringConvert((long).Reference
&& item.ShoppingCartWebId > SqlFunctions.StringConvert((long)m.Reference)
))){
//do something special
}
}