My Vehicle
type:
public class Vehicle : EntityObject
{
private Lazy<string> _nameFromDelegate = null;
private Lazy<IList<Component>> _components = null;
public Vehicle(int id, string name, Lazy<string> nameFromDelegate, Lazy<IList<Component>> components)
: base(id)
{
this.Name = name;
this._nameFromDelegate = nameFromDelegate;
}
public string Name { get; private set; }
public string NameFromDelegate
{
get
{
return this._nameFromDelegate.Value;
}
}
public IList<Component> Components
{
get
{
return this._components.Value;
}
}
}
I want to project my type in L2S using the constructor and pass in certain mappings as delegates so they're evaluated in memory rather than L2S trying to translate them to SQL.
In the example below i'm trying to map the "vehicle.Name" value from SQL onto two properties on my Vehicle
type: the "Name" string
property and the "NameFromDelegate" string
property (which encapsulates the Lazy<string>
).
I'm hoping to prove that it doesn't make any difference to L2S whether i pass in the "vehicle.Name" to the string
ctor param or to the Lazy<string>
ctor param. But perhaps it does:
I don't understand why there is a need to cast from string
to Func<string>
. Ideas?
Stack trace for reference:
at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
at System.String.System.IConvertible.ToType(Type type, IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Data.Linq.DBConvert.ChangeType(Object value, Type type)
at Read_Vehicle(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 DelegateQueries.Models.V开发者_JAVA百科ehicleRepoWithDelegates.GetAll() in %path%\DelegateQueries\Models\VehicleRepoWithDelegates.cs:line 26
at DelegateQueries.Tests.RepoTests.VehicleRepo_CanReturn_NameFromDelegateProp_InLinq_WithDelegate() in %path%\DelegateQueries\DelegateQueries.Tests\RepoTests.cs:line 31
This appears to work around the problem:
static Lazy<T> Lazyfy<T>(T input)
{
return new Lazy<T>(() => input);
}
public IQueryable<Vehicle> Vehicles()
{
return from veh in ctx.vehicles
select new Vehicle(veh.id, veh.name, Lazyfy(veh.name), null);
}
UPDATE you can also do this:
static Func<T> Functify<T>(T input)
{
return () => input;
}
public IQueryable<Vehicle> Vehicles()
{
return from veh in ctx.vehicles
select new Vehicle(veh.id, veh.name, new Lazy<string>(Functify(veh.name)), null);
}
but you can't do this:
var r = from veh in ctx.vehicles
select new Func<int>(() => veh.id);
r.ToList();
It appears that L2S is treating the lambda expression creation as a value assignment, instead as a method call and is trying to convert the value from the db to it. I'm saying it's a bug since this works on linq to objects.
精彩评论