在Linq中映射表达式

时间:2012-02-14 15:28:49

标签: .net linq

我正在将我的业务对象上的Linq查询映射到我的Entity Framework数据库。有没有其他人走这条路 - 或者更重要的是,是否有更好的方法来解决这个问题。

我想要实现的是能够从我的UI层对我的业务层运行简单查询,而无需向管理器(BL层)或存储库(DA层)添加其他方法

我得到的好处是我可以在UI层中描述我想要的投影,并且不需要在我的经理中创建单独的类或特殊方法,或者在我的DA层中进行额外的编码以有效地执行查询(在这种情况下是键+聚合数据)

var promoSource = new Queryable<BL.Promo>(new PromoQueryProvider());//When executed, Maps a BL Promo code query to an EF.PromoCode query
var query = from x in promoSource
  where x.PromoCode != null && x.OrderDate >= startDate && x.OrderDate <= endDate
  group x by x.PromoCode
  into result
  select new
  {
    PromoCode = result.Key.Trim(),
    AverageOrderValue = result.Average(x => x.OrderSubtotal),
    NumberOfOrders = result.Count()
  };
var results = query.ToList(); //Executes the query in the data layer and passes back the projected data
promosDataView.DataSource = results;
promosDataView.DataBind();

以前我需要添加一个类来表示视图对象,Manager中的一个方法可以从实体构建摘要数据,将调用转发到数据层以获取来自数据库的数据。

似乎工作正常,在有限的情况下,但我也觉得我在适当的分离方面错过了这条船 - 在电子商务应用程序中,为了简单的报告方案,我是否会过度使用maintaning分离层?如果我在aspx页面上使用EF数据源,我不会得到同样的好处吗?

1 个答案:

答案 0 :(得分:0)

我已经开始沿着这条道路前进并取得了一些初步的成功。对我而言,关键是将引用A.MemberOfA的表达式的一部分转换为引用B.MemberOfB的表达式。例如,假设您有一个业务对象A

class A { public bool Selected { get; set; } }

和数据对象(实体)B

class B { public int SelectedInd { get; set; } }

如您所见,在数据库中,B的选定状态由指标int定义。如果您想获得所有选定的A,您可能有一个谓词:

Expression<Func<A, bool>> aPredicate = a => a.Selected;

现在您需要在实体集上执行该谓词。如果B

,则可能会选择SelectedInd > 0您的商家规则
Expression<Func<B, bool>> bPredicate = b => b.SelectedInd > 0;

对我而言,诀窍是ExpressionVisitor类。通过扩展此类并覆盖Visit方法,您可以使用对AA.Selected的引用替换引用BB.SelectedInd > 0的部分:

class ExpressionTranslator : ExpressionVisitor
{
    public Expression<Func<B, bool>> TranslatePredicate(Expression<Func<A, bool>> predicate)
    {
        return (Expression<Func<B, bool>>)this.Visit(predicate);
    }

    public override Expression Visit(Expression exp)
    {
        if (exp is Expression<Func<A, bool>>)
        {
            Expression<Func<A, bool>> predicate = (Expression<Func<A, bool>>)exp;
            Expression body = this.Visit(predicate.Body);
            ParameterExpression parameter = (ParameterExpression)this.Visit(predicate.Parameters[0]);
            return Expression.Lambda<Func<B, bool>>(body, parameter);
        }
        else if (exp is ParameterExpression)
        {
            ParameterExpression param = (ParameterExpression)exp;
            if (param.Type == typeof(A))
                return bPredicate.Parameters[0];
        }
        else if (exp is MemberExpression)
        {
            MemberExpression mbrExpr = (MemberExpression)exp;
            if (mbrExpr.Member == typeof(A).GetProperty("Selected"))
                return this.Visit(bPredicate.Body);
        }
        else
            return base.Visit(exp);
    }
}

当然,您可以想象使这种逻辑更通用。在我自己的实现中,我注册对象映射选择器,以便ExpressionTranslator.Visit根据exp动态选择要返回的表达式。

希望这有帮助。