Questo mi sta davvero sconcertando. So che gli handle LINQ-to-SQL selezionano elaborando l'albero delle espressioni e tentando di tradurre le cose tramite la query generata, motivo per cui alcune traduzioni di funzioni non funzionano (string.IsNullOrWhitespace
è un disturbo normale).Perché LINQ-to-SQL a volte mi consente di proiettare utilizzando una funzione, ma a volte no?
Ho riscontrato una situazione nel mio codice in cui LINQ-to-SQL è stato in grado di chiamare la mia funzione di supporto tramite una proiezione Seleziona ... a volte. In effetti, funziona quando il metodo ha un solo nome, ma non funziona con esso ha un altro nome. Credo che questo è meglio illustrato da seguente programma (questo è quanto di più semplice come ho potuto fare):
// #define BREAK_THE_CODE
using System;
using Sandbox.Data;
using System.Collections.Generic;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
List<MyValue> myValueList;
try
{
myValueList = dataContext.Numbers.Select(x => new MyValue
{
#if BREAK_THE_CODE
Type = ToValueType(x.Value),
#else
Type = DoIt(x.Value),
#endif
}).ToList();
}
catch (NotSupportedException)
{
System.Console.WriteLine("Not supported, oh noes!");
System.Console.ReadKey();
return;
}
System.Console.WriteLine(myValueList.Count);
System.Console.ReadKey();
}
}
#if BREAK_THE_CODE
public static MyValueType ToValueType(int value)
#else
public static MyValueType DoIt(int value)
#endif
{
return MyValueType.One;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
One,
Two,
Unknown,
}
}
}
Il database di supporto ha una sola tabella denominata [Number]
con una sola colonna [Value] INT NOT NULL
.
Come scritto, il programma funziona per me, ma commentando la #define
in alto passerà il nome della chiamata di metodo e quindi il programma sarà gettare un NotSupportedException
durante l'esecuzione ToList()
.
Ho provato diversi nomi di metodi per provare a determinare un modello, ma non sono stato in grado di farlo.
Sembra che il metodo abbia un nome qualsiasi che inizi con To
e che lanci lo NotSupportedException
, ma sembra funzionare con qualsiasi altro nome. Questo è ancora strano.
Qualcuno può spiegare cosa sta succedendo?
Ecco un altro esempio senza l'interruttore #define
, è sufficiente eseguire entrambi i metodi in modalità back to back e sto ancora vedendo lo stesso problema. Nello specifico, DoIt
funziona, ma non lo è ToValueType
.
using System;
using Sandbox.Data;
using System.Linq;
namespace Sandbox.Console
{
class Program
{
static void Main(string[] args)
{
using (var dataContext = new SandboxDataContext())
{
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = DoIt(x.Value),
}).ToList();
System.Console.WriteLine("DoIt Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("DoIt Failed, oh noes!");
}
try
{
var myValueList = dataContext.Numbers.Select(x => new MyValue
{
Type = ToValueType(x.Value),
}).ToList();
System.Console.WriteLine("ToValueType Succeeded, found {0} results", myValueList.Count);
}
catch (NotSupportedException)
{
System.Console.WriteLine("ToValueType Failed, oh noes!");
}
System.Console.ReadKey();
}
}
public static MyValueType DoIt(int value)
{
return MyValueType.SpecialType;
}
public static MyValueType ToValueType(int value)
{
return MyValueType.SpecialType;
}
public sealed class MyValue
{
public MyValueType Type { get; set; }
}
public enum MyValueType
{
SpecialType,
}
}
}
È ToValueType l'unica stringa che non funziona? Se è vero quello che dici, e sono prudente supporre che, questo sarebbe un bug L2S (davvero insolito). – usr
Normalmente, L2S può eseguire le funzioni nella selezione finale. Questa è una caratteristica fantastica di EF che manca ancora. – usr
Sono stato in grado di riprodurre il comportamento che hai descritto anche in LINQPad, ogni volta che usi un metodo che inizia con 'To' (sensibile al maiuscolo/minuscolo) genera un'eccezione. –