To naprawdę mnie zastanawia. Wiem, że LINQ-SQL obsługuje selekcje, przetwarzając drzewo wyrażeń i próbując przetłumaczyć je za pomocą wygenerowanego zapytania, dlatego niektóre tłumaczenia funkcji nie działają poprawnie (string.IsNullOrWhitespace
to zwykła irytacja).Dlaczego LINQ-SQL czasami pozwala mi na projekt przy użyciu funkcji, ale czasami nie?
Uderzyłem w sytuację w moim kodzie, w którym LINQ-SQL mógł wywoływać moją funkcję pomocnika za pośrednictwem Wybierz projekcję ... czasami. W rzeczywistości działa, gdy metoda ma jedną nazwę, ale nie działa z nią ma inną nazwę. Myślę, że jest to najlepiej ilustruje poniższy program (to jest tak proste, jak mogłoby uczynić go):
// #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,
}
}
}
Baza podkładowa ma tylko jedną tabelę o nazwie [Number]
z pojedynczej kolumny [Value] INT NOT NULL
.
Jak napisano, program działa na mnie, ale odkomentowanie #define
na szczycie przełączy nazwę wywołania metody, a następnie program będzie rzucać NotSupportedException
podczas wykonywania ToList()
.
Próbowałem różnych nazw metod, aby spróbować określić wzór, ale nie udało się.
Wygląda na to, że jeśli metoda otrzyma nazwę o numerze zaczynającym się od To
, to wyśle ona NotSupportedException
, ale wydaje się działać z dowolną inną nazwą. To wciąż jest dziwne.
Czy ktoś może wyjaśnić, co się dzieje?
Oto kolejna próbka bez przełącznika #define
, to po prostu robi obie metody z powrotem i nadal widzę ten sam problem. W szczególności działa DoIt
, ale ToValueType
nie.
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,
}
}
}
Czy ToValueType jedyny ciąg, który nie działa? Jeśli to prawda, co mówisz, i jestem ostrożny, zakładając, że to byłby błąd L2S (naprawdę nietypowy). – usr
Zwykle L2S może wykonywać funkcje w finale Wybierz dokładnie. Jest to niesamowita funkcja, której brakuje w EF. – usr
Byłem w stanie odtworzyć opisane zachowanie nawet w LINQPad, za każdym razem, gdy używasz metody zaczynającej się od 'To' (rozróżniana jest wielkość liter), zgłaszany jest wyjątek. –