LINQ:Expression.Call(typeof(Queryable),“选择”

发布于 2024-09-27 08:43:58 字数 2223 浏览 2 评论 0原文

我正在尝试创建一个小型“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=>...”将替换为“A.ChildEntities.Select( B=>...”

有什么想法吗?

I'm attempting to create a small "automapper-esq" utility that will take a LinqToSql entity and map it to a "projection class".

So far I have something like this:

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

where BuildProjection returns:

Expression<Func<TSource, TResult>>

which essentially creates a lambda like this:

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

Now the tricky part...I'd like to be able to project association properties of the "parent" entity as well. Essentially what I need is to get something like this:

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

I have gotten as far as getting this part:

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

By doing this:

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

Here is where I am stuck at the moment...I am getting a little confused when attempting to replace Expression.Constant(list) with some other expression that represents the actual datatype for the property so that "System.Collections.Generic.List1[ChildEntity].Select(B=>..." will be replaced with "A.ChildEntities.Select(B=>..."

Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独木成林 2024-10-04 08:43:58

我一直在寻找如何使用表达式(正确的术语?)来做到这一点,并且我最终确实弄清楚了。

我必须将其更改

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

希望这可以帮助其他人......

I was looking more for how to do this using Expressions (correct terminology?) and I did eventually figure it out.

I had to change this:

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

to this:

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

Hope this helps someone else out...

暮年 2024-10-04 08:43:58

这是建议的查询。您可能想更改您的 IEnumerable<>在 EntityProjection to a 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();

Here's a suggested query. And you might want to change your IEnumerable<> in EntityProjection to a List<> to avoid a lazy load (if it matters...). Anyway, I hope this is helpful.

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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文