LINQ: Expression.Call (typeof (Queryable), «Выбрать» - PullRequest
3 голосов
/ 13 октября 2010

Я пытаюсь создать небольшую утилиту «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>>

, который, по сути, создает лямбду следующим образом:

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 => ... »будет заменен на« A.ChildEntities.Select (B => ... »

Есть идеи?

Ответы [ 2 ]

7 голосов
/ 27 октября 2010

Я больше искал, как это сделать с помощью выражений (правильная терминология?), И в конце концов понял это.

Я должен был изменить это:

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 });

Надеюсь, это поможет кому-то еще ...

0 голосов
/ 15 октября 2010

Вот предложенный запрос.И вы можете изменить свой IEnumerable <> в EntityProjection на List <>, чтобы избежать отложенной загрузки (если это имеет значение ...)Во всяком случае, я надеюсь, что это полезно.

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();
...