LINQ:Expression.Call(typeof(可查询),“选择”

时间:2010-10-13 01:01:46

标签: linq-to-sql lambda projection

我正在尝试创建一个小的“automapper-esq”实用程序,它将采用LinqToSql实体并将其映射到“投影类”。

到目前为止,我有这样的事情:

class Entity
{
    public int ID { get; set; }
    public string WantedProperty { get; set; }
    public string UnWantedPropertyData { get; set; }
    ...More Unwanted Properties...
    public IEnumerable<ChildEntity> ChildEntities { get; set; }
}

class EntityProjection
{
    public int ID { get; set; }
    public string WantedProperty { get; set; }
    public IEnumerable<ChildEntityProjection> ChildEntities { get; set; }
}

class ChildEntityProjection
{
    public int ID { get; set; }
    public string WantedProperty { get; set; }
    public string UnWantedPropertyData { get; set; }
    ...More Unwanted Properties...
}


var results = context.Table.Select(ProjectionHelper.BuildProjection<Entity,EntityProjection>());

BuildProjection返回的地方:

Expression<Func<TSource, TResult>>

基本上创建了一个像这样的lambda:

A => new EntityProjection() { ID = A.ID, WantedProperty = A.WantedProperty }

现在棘手的部分......我希望能够投射“父”实体的关联属性。基本上我需要的是得到这样的东西:

A => new EntityProjection() {
  ID = A.ID,
  WantedProperty = A.WantedProperty,
  ChildEntities = A.ChildEntities.Select(B => new ChildEntityProjection {
    ID = B.ID,
    WantedProperty = B.WantedProperty
  }
}

我已经得到了这个部分:

A => new EntityProjection() {
  ID = A.ID,
  WantedProperty = A.WantedProperty,
  ChildEntities = System.Collections.Generic.List1[ChildEntity].Select(B => new ChildEntityProjection {
    ID = B.ID,
    WantedProperty = B.WantedProperty
  }
}

通过这样做:

IQueryable<ChildEntity> list = new List<ChildEtity>().AsQueryable();
Expression _selectExpression = Expression.Call(
  typeof(Queryable),
  "Select",
  new Type[] { typeof(ChildEntity), typeof(ChildEntityProjection) },
  Expression.Constant(list),
  _nestedLambda);

这就是我现在陷入困境的地方......当我尝试用表示属性的实际数据类型的其他表达式替换Expression.Constant(list)以及“System.Collections”时,我感到有些困惑。 Generic.List1 [ChildEntity] .Select(B =&gt; ...“将替换为”A.ChildEntities.Select(B =&gt; ...“

有什么想法吗?

2 个答案:

答案 0 :(得分:7)

我正在寻找更多如何使用表达式(正确的术语?)来做到这一点,并且我最终确定了它。

我不得不改变这个:

IQueryable<ChildEntity> list = new List<ChildEtity>().AsQueryable(); 
Expression _selectExpression = Expression.Call( 
  typeof(Queryable), 
  "Select", 
  new Type[] { typeof(ChildEntity), typeof(ChildEntityProjection) }, 
  Expression.Constant(list), 
  _nestedLambda); 

到此:

MethodInfo selectMethod = null;
foreach (MethodInfo m in typeof(Enumerable).GetMethods().Where(m => m.Name == "Select"))
  foreach (ParameterInfo p in m.GetParameters().Where(p => p.Name.Equals("selector")))
    if (p.ParameterType.GetGenericArguments().Count() == 2)
      selectMethod = (MethodInfo)p.Member;

var _selectExpression = Expression.Call(
  null,
  selectMethod.MakeGenericMethod(new Type[] { typeof(ChildEntity), typeof(ChildEntityProjection) }),
  new Expression[] { _myPropertyExpression, _myFuncExpression });

希望这有助于其他人......

答案 1 :(得分:0)

这是一个建议的查询。你可能想要改变你的IEnumerable&lt;&gt;在EntityProjection中的列表&lt;&gt;避免懒惰负载(如果重要......)。无论如何,我希望这是有帮助的。

EntityProjection projection = context.Table
    .Where(entity => entity.ID == 123)
    .Select(entity => new EntityProjection()
    {
        ID = entity.ID,
        WantedProperty = entity.WantedProperty,
        ChildEntities = entity.ChildEntities
            .Select(child => new ChildEntityProjection()
            {
                ID = child.EmployeeID,
                WantedProperty = child.WantedProperty
            })
            .ToList()
    })
    .SingleOrDefault();