【问题标题】:How to combine multiple c# Lambda Expressions (Expression<Func<T, T>>)如何组合多个 c# Lambda 表达式(Expression<Func<T, T>>)
【发布时间】:2018-08-23 01:33:44
【问题描述】:

我有以下函数,它实际上是 Z.EntityFramework.Plus 批量更新的包装器:

    public static int UpdateBulk<T>(this IQueryable<T> query, Expression<Func<T, T>> updateFactory) where T : IBaseEntity, new()
    {
        Expression<Func<T, T>> modifiedExpression = x => new T() { ModifiedBy = "Test", ModifiedDate = DateTime.Now };
        var combine = Expression.Lambda<Func<T, T>>(
            Expression.AndAlso(
                Expression.Invoke(updateFactory, updateFactory.Parameters),
                Expression.Invoke(modifiedExpression, modifiedExpression.Parameters)
            ),
            updateFactory.Parameters.Concat(modifiedExpression.Parameters)
        );  //This returns an error

        return query.Update(combine);
    }

这样称呼:

        decimal probId = ProbId.ParseDecimal();

        db.Problems
            .Where(e => e.ProbId == probId)
            .UpdateBulk(e => new Problem() {
                CatId = Category.ParseNullableInt(),
                SubCatId = SubCategory.ParseNullableInt(),
                ListId = Problem.ParseNullableInt()
            });

其中IBaseEntity定义如下:

public abstract class IBaseEntity
{
    public System.DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }

    public System.DateTime ModifiedDate { get; set; }
    public string ModifiedBy { get; set; }

    public string DeletedBy { get; set; }
}

顺便说一句,“问题”类实现了 IBaseEntity。

我想要做的是自动将 ModifiedBy 和 ModifiedDate 附加到 UpdateBulk 函数中的 updateFactory,这样就不必在每次调用 UpdateBulk 时都这样做。

我尝试在上面的 UpdateBulk 函数中将解析的“updateFactory”表达式与“modifiedExpression”组合,但它返回错误:

二元运算符 AndAlso 没有为类型“问题”定义

是否可以像这样合并表达式,如果可以,我做错了什么? 如果没有,如何将 ModifiedBy = "Test", ModifiedDate = DateTime.Now 合并到 updateFactory 表达式中?

谢谢, 棒

【问题讨论】:

  • 尝试将.Where(e =&gt; e.ProbId == probId) 更改为.Where(e=&gt; e.ProbId == null ? (e.ProbId == probId) : false)?有时这个问题是由返回的空数据引起的。
  • 嗨 MatrixTai。感谢您的回复,ProbId 在数据库中被列为不可为空。无论如何我尝试了你的建议,但仍然遇到同样的错误。杆
  • AndAlso 用于Expression&lt;Func&lt;T,bool&gt;&gt;,对于Expression&lt;Func&lt;T,T&gt;&gt;,您需要定义一个表达式访问者here

标签: c# linq expression entity-framework-plus


【解决方案1】:

你不能使用AndAlso,因为那是为了BinaryExpression - Expression&lt;Func&lt;T,bool&gt;&gt;,在这种情况下你需要Expression Visitor,正如Marc Gravell所定义的here(所以他应该得到所有的功劳)

我正在使用相同的方法为您的情况提供解决方案,假设为 Problem class schema,粘贴 Linqpad 代码:

void Main()
{
  var final = UpdateBulk((Problem p) => new Problem{CatId = 1,SubCatId = 2, ListId=3});

 // final is of type Expression<Func<T,T>>, which can be used for further processing

  final.Dump();
}

public static Expression<Func<T, T>> UpdateBulk<T>(Expression<Func<T, T>> updateFactory) where T : IBaseEntity, new()
{
    Expression<Func<T, T>> modifiedExpression = x => new T() { ModifiedBy = "Test", ModifiedDate = DateTime.Now };

    var result = Combine(updateFactory, modifiedExpression);

    return result;
}


static Expression<Func<TSource, TDestination>> Combine<TSource, TDestination>(
    params Expression<Func<TSource, TDestination>>[] selectors)
{
    var param = Expression.Parameter(typeof(TSource), "x");
    return Expression.Lambda<Func<TSource, TDestination>>(
        Expression.MemberInit(
            Expression.New(typeof(TDestination).GetConstructor(Type.EmptyTypes)),
            from selector in selectors
            let replace = new ParameterReplaceVisitor(
                  selector.Parameters[0], param)
            from binding in ((MemberInitExpression)selector.Body).Bindings
                  .OfType<MemberAssignment>()
            select Expression.Bind(binding.Member,
                  replace.VisitAndConvert(binding.Expression, "Combine")))
        , param);
}

class ParameterReplaceVisitor : ExpressionVisitor
{
    private readonly ParameterExpression from, to;
    public ParameterReplaceVisitor(ParameterExpression from, ParameterExpression to)
    {
        this.from = from;
        this.to = to;
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == from ? to : base.VisitParameter(node);
    }
}

public abstract class IBaseEntity
{
    public System.DateTime CreatedDate { get; set; }
    public string CreatedBy { get; set; }

    public System.DateTime ModifiedDate { get; set; }
    public string ModifiedBy { get; set; }

    public string DeletedBy { get; set; }
}

public class Problem : IBaseEntity
{
    public int CatId { get; set; }

    public int SubCatId { get; set; }

    public int ListId { get; set; }
}

【讨论】:

  • 感谢 Mrinal,这就是我正在寻找的解决方案。杆
猜你喜欢
  • 2010-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-17
相关资源
最近更新 更多