2008-11-21 65 views
4

我只有一个表映射到datacontext中。这里的属性和属性感兴趣的列:LinqToSql .Contains和nvarchar与varchar参数 - >索引转换计划

[Column(Storage="_CustomerNumber", DbType="VarChar(25)")] 
public string CustomerNumber 
{ 

此列,事实上,一个varchar(25),并有一个索引。

我有一些简单的代码:

DataClasses1DataContext myDC = new DataClasses1DataContext(); 
myDC.Log = Console.Out; 

List<string> myList = new List<string>() { "111", "222", "333" }; 
myDC.Customers 
    .Where(c => myList.Contains(c.CustomerNumber)) 
    .ToList(); 

生成此SQL文本:

SELECT [t0].[CustomerNumber], [t0].[CustomerName] 
FROM [dbo].[Customers] AS [t0] 
WHERE [t0].[CustomerNumber] IN (@p0, @p1, @p2) 
-- @p0: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [111] 
-- @p1: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [222] 
-- @p2: Input NVarChar (Size = 3; Prec = 0; Scale = 0) [333] 
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8 

注意,PARAMATERS是nvarchar的!

当此查询命中数据库时,它会生成一个可怕的计划,其中涉及将CustomerNumber上的数百万行索引转换为nvarchar,然后再搜索它。

我不允许更改表格,但我可以更改查询和dbml。我能做些什么来获取数据而无需获得此索引转换?

回答

2

这是我解决这个问题,现在给天的方式。这将参数转换为所需的类型,然后运行查询。它生成与最初生成的相同的sql,只是使用不同的参数类型。

DbCommand myCommand = myDataContext.GetCommand(query); 

foreach (DbParameter dbParameter in myCommand.Parameters) 
{ 
    if (dbParameter.DbType == System.Data.DbType.String) 
    { 
    dbParameter.DbType = System.Data.DbType.AnsiString; 
    } 
}  

myDataContext.Connection.Open(); 

System.Data.Common.DbDataReader reader = myCommand.ExecuteReader(); 
List<RecordType> result = myDataContext.Translate<RecordType>(reader).ToList(); 

myDataContext.Connection.Close(); 
+0

这工作,但有一个问题:在.Translate 方法将无法正确加载相关实体T.(。换句话说,如果你在添加.LoadsWith 你的上下文,以及TOther与T有关,那么这将失败)。 – dkr88 2012-12-04 22:34:19

0

这是我作为一个可能的工作。我希望看到其他的解决方案,以及:

List<IQueryable<Customer>> myQueries = 
    myList.Select(s => myDC.Customers.Where(c => c.CustomerNumber == s)).ToList(); 
IQueryable<Customers> myQuery = myQueries.First(); 
foreach(IQueryable<Customer> someQuery in myQueries.Skip(1)) 
{ 
    myQuery = myQuery.Concat(someQuery); 
} 
myQuery.ToList(); 

这将生成以下SQL:

SELECT [t4].[CustomerNumber], [t4].[CustomerName] 
FROM (
    SELECT [t2].[CustomerNumber], [t2].[CustomerName] 
    FROM (
     SELECT [t0].[CustomerNumber], [t0].[CustomerName] 
     FROM [dbo].[Customer] AS [t0] 
     WHERE [t0].[CustomerNumber] = @p0 
     UNION ALL 
     SELECT [t1].[CustomerNumber], [t1].[CustomerName] 
     FROM [dbo].[Customer] AS [t1] 
     WHERE [t1].[CustomerNumber] = @p1 
     ) AS [t2] 
    UNION ALL 
    SELECT [t3].[CustomerNumber], [t3].[CustomerName] 
    FROM [dbo].[Customer] AS [t3] 
    WHERE [t3].[CustomerNumber] = @p2 
    ) AS [t4] 
-- @p0: Input VarChar (Size = 3; Prec = 0; Scale = 0) [111] 
-- @p1: Input VarChar (Size = 3; Prec = 0; Scale = 0) [222] 
-- @p2: Input VarChar (Size = 3; Prec = 0; Scale = 0) [333] 
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.21022.8 
0

对于我工作的项目,我们必须使用ObjectContext代替DbContext,所以我不必GetCommand()DbParameters随时访问。我所做的是将查询转换为字符串,在查询中删除NVARCHAR指标,然后对ObjectContext执行查询。下面是给出的例子中详细的实施:

List<string> myList = new List<string>() { "111", "222", "333" }; 

IQueryable<Customers> badQuery = myDC.Customers 
    .Where(c => myList.Contains(c.CustomerNumber)); 

string query = ((System.Data.Objects.ObjectQuery)badQuery).ToTraceString(); 
query = query.Replace(",N'", ",'").Replace("(N'","('"); 

List<Customers> customers = myDC.ExecuteStoreQuery<Customers>(query).ToList(); 
+0

这是LinqToEntities。我正在使用LinqToSql。据我所知,LinqToEntities没有这个查询翻译问题。 – 2013-09-09 17:25:44