我的同事在.NET 4.0中使用LINQ to SQL進行更復雜的查詢時出錯,但似乎在更簡單的情況下很容易重現。考慮一個名爲TransferJob的表,其中包含一個合成ID和一個位域。使用匿名對象和常量列的LINQ to SQL中的奇怪行爲
如果我們做下面的查詢
using (var ctx = DBDataContext.Create())
{
var withOutConstant = ctx.TransferJobs.Select(x => new { Id = x.TransferJobID, IsAuto = x.IsFromAutoRebalance });
var withConstant = ctx.TransferJobs.Select(x => new { Id = x.TransferJobID, IsAuto = true });//note we're putting a constant value in this one
var typeA = withOutConstant.GetType();
var typeB = withConstant.GetType();
bool same = typeA == typeB; //this is true!
var together = withOutConstant.Concat(withConstant);
var realized = together.ToList();//invalid cast exception
}
無效轉換異常被拋出注意的地方。但奇怪的是,我們在調試器中查看時有類型相等。
簡單地改變倒數第二行從的IQueryable的移動使用LINQ到對象
var together = withOutConstant.ToList().Concat(withConstant.ToList());
var realized = together.ToList();//no problem here
然後一切工作正常預期。
經過一些初步的挖掘之後,我發現它看起來像LINQ to SQL的程序員正在考慮性能,並且實際上並沒有在withConstant版本中顯式設置true的情況下生成的SQL拉動常量值。
最後,如果切換命令一切似乎工作:
var together = withConstant.Concat(withOutConstant); //no problem this way
不過,我還是想知道,如果更好的細節究竟怎麼回事。我覺得奇怪的是,這些被認爲是相同的類型,但會導致無效的轉換異常。封面下實際發生了什麼?我怎麼能去證明自己?
堆棧跟蹤:
at System.Data.SqlClient.SqlBuffer.get_Boolean()
at Read_<>f__AnonymousType2`2(ObjectMaterializer`1)
at System.Data.Linq.SqlClient.ObjectReaderCompiler.ObjectReader`2.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at KBA.GenericTestRunner.Program.Main(String[] args) in c:\Users\nick\Source\Workspaces\KBA\Main\KBA\KBA.GenericTestRunner\Program.cs:line 59
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
生成的SQL如下:
SELECT [t2].[TransferJobID] AS [Id], [t2].[IsFromAutoRebalance] AS [IsAuto]
FROM (
SELECT [t0].[TransferJobID], [t0].[IsFromAutoRebalance]
FROM [dbo].[TransferJob] AS [t0]
UNION ALL
SELECT [t1].[TransferJobID], @p0 AS [value]
FROM [dbo].[TransferJob] AS [t1]
) AS [t2]
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.34209
隨着順序顛倒(不崩潰)的SQL是:
SELECT [t2].[TransferJobID] AS [Id], [t2].[value] AS [IsAuto]
FROM (
SELECT [t0].[TransferJobID], @p0 AS [value]
FROM [dbo].[TransferJob] AS [t0]
UNION ALL
SELECT [t1].[TransferJobID], [t1].[IsFromAutoRebalance]
FROM [dbo].[TransferJob] AS [t1]
) AS [t2]
-- @p0: Input Int (Size = -1; Prec = 0; Scale = 0) [1]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.34209
要我以前的評論,當做的時候不會拉動常數
withConstant.ToList()
SELECT [t0].[TransferJobID] AS [Id]
FROM [dbo].[TransferJob] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.34209
你可以發佈堆棧跟蹤嗎?這將給出更多關於問題可能出在哪裏的提示。 –
你可以在'IQueryable'中發佈'T'實例的類定義/模型嗎?另外,當你說'合成身份證'時,你的意思是一個自動增加你爲PK? –
evanmcdonnal
添加堆棧跟蹤 – nlh3