我正在创建一个动态投影(选择)lambda表达式,并将其与Linq一起用于NHibernate。看起来等效的静态表达式没有相同的表现。静态表达式已正确地转换为sql的外部联接,但是动态表达式正在使用多个from语句(无联接)进行转换。这些表达式似乎是等效的。我需要找到一种方法来阐明表达式为何不同的原因,或者更好地理解表达式从编译时编译到运行时“编译”的不同之处-猜测这与遍历属性有关,但这仅仅是一个问题。猜。
public static class Dyna
{
public static Expression<Func<Tsrc, Tdto>> SelectProps<Tsrc, Tdto>(List<string> props)
{
Type typeEnt = typeof(Tsrc);
Type typeDto = typeof(Tdto);
var ctor = Expression.New(typeDto);
ParameterExpression parameter = Expression.Parameter(typeEnt, "x");
var propertiesDto = typeDto.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var tprops = typeEnt.GetProperties();
var tflds = typeEnt.GetFields();
var memberAssignments = propertiesDto.Select(p =>
{
var PPath = GetPropertyPath(p);
if (PPath != null)
{
if (props.Contains(p.Name))
{
var mem = GetMemberExpression(CreateExpression(typeEnt, PPath));
return Expression.Bind(p, mem);
}
else { return null; }
}
else
{
return null;
}
});
var memexps = memberAssignments.Where(m => m != null);
var memberInit = Expression.MemberInit(ctor, memexps);
return Expression.Lambda<Func<Tsrc, Tdto>>(memberInit, parameter);
}
public static MemberExpression GetMemberExpression(Expression expression)
{
if (expression is MemberExpression)
{
return (MemberExpression)expression;
}
else if (expression is LambdaExpression)
{
var lambdaExpression = expression as LambdaExpression;
if (lambdaExpression.Body is MemberExpression)
{
return (MemberExpression)lambdaExpression.Body;
}
else if (lambdaExpression.Body is UnaryExpression)
{
return ((MemberExpression)((UnaryExpression)lambdaExpression.Body).Operand);
}
}
return null;
}
public static LambdaExpression CreateExpression(Type type, string propertyName)
{
var param = Expression.Parameter(type, "x");
Expression body = param;
foreach (var member in propertyName.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
return Expression.Lambda(body, param);
}
静态表达式代码
var conn = this.Connection.ConnectionString;
// NH Session
using( var Session = SetupNHConfig(conn).OpenSession())
{
// NH Linq Query
var evtq = Session.Query<Event>();
var res = evtq.Select(x => new EventDto() {
Id = x.Id,
ProjectName = x.ProjectName,
EventName = x.EventName,
EventType = x.EventType.EventTypeName,
Status = x.EventStatus.EventStatusTypeName}
);
res.Dump();
//x => new EventDto() {ProjectName = x.ProjectName, EventName = x.EventName, Status = x.EventStatus.EventStatusTypeName}
res.ToList().Dump();
}
生成的SQL
-- Generated by Static Expression
SELECT event0_.ProjectName AS col_0_0_,
event0_.EventName AS col_1_0_,
eventtype1_.EventTypeName AS col_2_0_,
eventstatu2_.EventStatusTypeName AS col_3_0_
FROM trg_eventmgr_Event event0_
LEFT OUTER JOIN trg_eventmgr_EventType eventtype1_ ON event0_.EventType_id = eventtype1_.ID
LEFT OUTER JOIN trg_eventmgr_EventStatusType eventstatu2_ ON event0_.EventStatus_id = eventstatu2_.ID;
-- Generated by Dynamic Expression
SELECT event0_.ID AS col_0_0_,
event0_.ProjectName AS col_1_0_,
event0_.EventName AS col_2_0_,
eventtype1_.EventTypeName AS col_3_0_,
eventstatu2_.EventStatusTypeName AS col_4_0_
FROM trg_eventmgr_Event event0_,
trg_eventmgr_EventType eventtype1_,
trg_eventmgr_EventStatusType eventstatu2_
WHERE event0_.EventType_id = eventtype1_.ID
AND event0_.EventStatus_id = eventstatu2_.ID;