我在datacontext中映射了一个表。这是感兴趣的列上的属性和属性:
[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
请注意,参数是nvarchar!
当此查询到达数据库时,它会生成一个可怕的计划,其中涉及将CustomerNumber上的数百万行索引转换为nvarchar ,然后再在其中搜索。
我不允许更改表,但我可以更改查询和dbml。如果不进行此索引转换,我该怎么做才能获取数据?
答案 0 :(得分:3)
以下是我现在解决这个问题的方法。这会将参数转换为所需类型,然后运行查询。它生成与最初生成的sql相同的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();
答案 1 :(得分: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
答案 2 :(得分: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();