Mój kolega dostał błąd z bardziej złożoną kwerendą przy użyciu LINQ do SQL w .NET 4.0, ale wydaje się być łatwo odtwarzalny w prostszych okolicznościach. Rozważmy tabelę o nazwie TransferJob z identyfikatorem syntetycznym i polem bitowym.Dziwne zachowanie w LINQ do SQL z anonimowymi obiektami i stałymi kolumnami
Jeśli wykonujemy następujące zapytanie
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
}
nieprawidłowy oddanych zostanie zgłoszony wyjątek, jeżeli nie zaznaczono. Dziwnie jednak mamy równość typu podczas przeglądania w debugerze.
prostu zmieniając przedostatniej kolejce, aby przejść z IQueryable do LINQ do obiektów
var together = withOutConstant.ToList().Concat(withConstant.ToList());
var realized = together.ToList();//no problem here
wtedy wszystko działa dobrze, jak oczekiwano.
Po pewnym wstępnym wykopaniu, widzę, że wygląda na to, że programiści LINQ do SQL brali pod uwagę wydajność i faktycznie nie mają wygenerowanego SQL ciągnącego stałą wartość w przypadku z jawnym ustawieniem true w wersji withConstant.
Wreszcie, jeśli mogę przełączyć zamówić wszystko wydaje się działać:
var together = withConstant.Concat(withOutConstant); //no problem this way
Jednak nadal bym chciał wiedzieć, czy lepiej szczegół, co naprawdę się dzieje. Uważam raczej za dziwne, że będą one traktowane jako równe typy, ale powodują wyjątek dotyczący nieprawidłowych rzutów. Co się właściwie dzieje pod kołdrą? Jak mógłbym udowodnić to sobie?
stosu Ślad:
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()
Generated SQL jest następujący:
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
Z odwróconej kolejności (co nie psuje) SQL jest:
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
Aby mój wcześniejszy komentarz, stała nie jest ciągnięta podczas wykonywania
withConstant.ToList()
SELECT [t0].[TransferJobID] AS [Id]
FROM [dbo].[TransferJob] AS [t0]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 4.0.30319.34209
Czy możesz wysłać ślad stosu? To dałoby kilka wskazówek na temat tego, gdzie może leżeć problem. –
Czy mógłbyś opublikować definicję klasy/model dla instancji 'T' w twoim' IQueryable 's? Ponadto, kiedy mówisz "syntetyczny identyfikator", masz na myśli automatyczny inkrement dla ciebie pk? –
evanmcdonnal
Dodano ślad stosu – nlh3