链接到实体,如何修复Startswith解析为SQL CHARINDEX并忽略索引

时间:2014-04-10 05:35:02

标签: sql linq entity-framework indexing

我有以下型号

public class Exchange
{
    public int Id { get; set; }

    [Index("ExchangeIdx", 1)]
    public int ExchangeSetId { get; set; }

    [Required]
    [MaxLength(10)]
    [Index("ExchangeIdx", 2)]
    public string BasePrefix { get; set; }

    [Required]
    [MaxLength(10)]
    [Index("ExchangeIdx", 3)]
    public string DestPrefix { get; set; }

}

我正在调用此功能

var exchange = context.Exchanges.FirstOrDefault(x => 
   x.ExchangeSetId == exchangeSetId && 
   x.BasePrefix.StartsWith(baseNumber.Substring(4)) && 
   baseNumber.StartsWith(x.BasePrefix) &&
   destNumber.StartsWith(x.DestPrefix));

以上是试图重现以下sql

SELECT TOP 1 * FROM Exchanges 
   where ExchangeSetId = 1 
   and BasePrefix like left('0732055827', 4) + '%' 
   and '0732055827' like BasePrefix +'%' 
   and '0732612680' like DestPrefix +'%'
然而,它产生了以下讨厌的工作

exec sp_executesql N'SELECT TOP (1) 
    [Extent1].[Id] AS [Id], 
    [Extent1].[ExchangeSetId] AS [ExchangeSetId], 
    [Extent1].[BasePrefix] AS [BasePrefix], 
    [Extent1].[DestPrefix] AS [DestPrefix]
    FROM [dbo].[Exchanges] AS [Extent1]
    WHERE ([Extent1].[ExchangeSetId] = @p__linq__0) 
    AND (( CAST(CHARINDEX(SUBSTRING(@p__linq__1, 4 + 1, ( CAST(LEN(@p__linq__1) AS int)) - 4), [Extent1].[BasePrefix]) AS int)) = 1) 
    AND (( CAST(CHARINDEX([Extent1].[BasePrefix], @p__linq__2) AS int)) = 1) AND (( CAST(CHARINDEX([Extent1].[DestPrefix], @p__linq__3) AS int)) = 1)',N'@p__linq__0 int,@p__linq__1 nvarchar(4000),@p__linq__2 nvarchar(4000),@p__linq__3 nvarchar(4000)',@p__linq__0=1,@p__linq__1=N'0732055827',@p__linq__2=N'0732055827',@p__linq__3=N'0732612680'

正如你可以看到它为StartsWith生成CHARINDEX

问题是这忽略了我设置的所有索引,并且需要花费很多秒才能运行500万条记录

我如何利用链接到实体,并满足上述要求,包括索引?

我唯一能想到的是使用存储过程或原始SQL语句,它会破坏整个实体的事物

有人有任何建议吗?

2 个答案:

答案 0 :(得分:0)

到目前为止我找到的唯一合适的解决方案是以下

var exchange = context.Database.SqlQuery<Exchange>(
    "SELECT TOP 1 * FROM Exchanges where ExchangeSetId = @ExchangeSetId and BasePrefix like left(@BaseNumber, 3) + '%' and @BaseNumber like BasePrefix +'%' and @DestNumber like DestPrefix +'%'",
    new SqlParameter("ExchangeSetId", exchangeSetId),
    new SqlParameter("AreaCode", areaCode),
    new SqlParameter("BaseNumber", baseNumber.Substring(2)),
    new SqlParameter("DestNumber", destNumber.Substring(2))).Select(x => new ExchangeViewModel(x)).FirstOrDefault();

答案 1 :(得分:0)

我相信如果您像这样执行Linq-to-SQL格式,它将为您提供正确的T-SQL:

var exchange = (from x in context.Exchanges 
    where x.ExchangeSetId == exchangeSetId && 
   x.BasePrefix.StartsWith(baseNumber.Substring(4)) && 
   baseNumber.StartsWith(x.BasePrefix) &&
   destNumber.StartsWith(x.DestPrefix))
   select new x{}).FirstOrDefault();