c# 在彼此之间转换谓词

标签 c# linq linq-to-sql predicate

我正在开发多层应用程序解决方案,我的解决方案如下所示

  • Business.DomainObject
  • Business.Process(*实际业务层)
  • 数据映射器
  • 数据存储库
  • Data.Sql.Entity(* 具有 .dbml 文件的实际数据层)

我的Business.Process项目(业务层)只知道Business.DomainObjectData.Repository项目,所以不知道与 Data.Sql.Entity 项目无关
我将业务(域)对象发送到存储库并在该项目内部进行映射,然后我在存储库层内使用关系数据层执行 CRUD 过程。

我的传统领域对象是这样的,它只有属性

public class UserBO
{
public string Email { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}

我的业务层类是这样的,

Repository r = new UserRepository();
r.Insert(myUserDomainObject);


一切正常,但我的“谓词”查询有一些问题。 我的存储库接口(interface)中有一个方法

bool IsExists(Expression<Func<BusinessObject,bool>> predicate);

并像这样在我的业务层中使用它;

Repository r = new UserRepository(); <br/>
r.IsExists(p => p.Email.Equals("email address"));

如您所见,它的参数是“业务对象”,但我的实际存储库(与数据库连接)使用我的 dbml 文件中的“dataobject”。

    public override bool IsExists(Expression<Func<DataObject, bool>> predicate){
return _table.Where(predicate).Any();
}

我想转换这两个谓词, 例如,我将发送 UserBO 并转换为 UserDataObject

我该怎么做?

最佳答案

您必须分析 LambdaExpression 的参数和主体并构建一个新的。您可以使用 predicate.Body 访问主体,使用 predicate.Parameters 访问参数。新表达式有一个 UserBO 类型的参数,而不是 UserDataObject。此外,主体中的 ParameterExpression(s) 必须使用新参数。
当然,这里假设是一个简单的场景,BO 和 DataObject 具有相同的属性。更复杂的转换是可能的,但需要对表达式树进行更深入的分析。
为了给大家一个起点,我一起列了一个示例,其中BusinessObject 和DataObject 非常相似。关键组件是派生自执行转换的 ExpressionVisitor 的类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace ConvertExpression
{
    public class BusinessObject
    {
        public int Value { get; set; }
    }

    public class DataObject
    {
        public int Value { get; set; }
    }

    internal class ExpressionConverter : ExpressionVisitor
    {
        public Expression Convert(Expression expr)
        {
            return Visit(expr);
        }

        private ParameterExpression replaceParam;

        protected override Expression VisitLambda<T>(Expression<T> node)
        {
            if (typeof(T) == typeof(Func<BusinessObject, bool>))
            {
                replaceParam = Expression.Parameter(typeof(DataObject), "p");
                return Expression.Lambda<Func<DataObject, bool>>(Visit(node.Body), replaceParam);
            }
            return base.VisitLambda<T>(node);
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            if (node.Type == typeof(BusinessObject))
                return replaceParam; // Expression.Parameter(typeof(DataObject), "p");
            return base.VisitParameter(node);
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            if (node.Member.DeclaringType == typeof(BusinessObject))
            {
                var member = typeof(DataObject).GetMember(node.Member.Name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).FirstOrDefault();
                if (member == null)
                    throw new InvalidOperationException("Cannot identify corresponding member of DataObject");
                return Expression.MakeMemberAccess(Visit(node.Expression), member);
            }
            return base.VisitMember(node);
        }
    }

    public class ConvertExpression
    {
        public static void Main()
        {
            BusinessObject[] bos = { new BusinessObject() { Value = 123 }, new BusinessObject() { Value = 246 } };
            DataObject[] dos = { new DataObject() { Value = 123 }, new DataObject() { Value = 246 } };
            Expression<Func<BusinessObject, bool>> boExpr = x => x.Value == 123;
            var conv = new ExpressionConverter();
            Expression<Func<DataObject, bool>> doExpr = (Expression<Func<DataObject, bool>>) conv.Convert(boExpr);

            var selBos = bos.Where(boExpr.Compile());
            Console.WriteLine("Matching BusinessObjects: {0}", selBos.Count());
            foreach (var bo in selBos)
                Console.WriteLine(bo.Value);
            var compDoExpr = doExpr.Compile();
            var selDos = dos.Where(doExpr.Compile());
            Console.WriteLine("Matching DataObjects: {0}", selDos.Count());
            foreach (var dataObj in selDos)
                Console.WriteLine(dataObj.Value);
            Console.ReadLine();
        }
    }
}

关于c# 在彼此之间转换谓词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20457693/

相关文章:

c# - 访问数据和连接字符串?

c# - 表达式树 : Binary operator not defined for types

c# - 检查字符串的单词是否存在于字符串列表中

c# - 对 OnMethodBoundaryAspect 中的类属性的引用

c# - 在 .Net 3.5 Web 项目中使用 HTTPS Web 服务

linq - 如何从 linq 查询中获取字符串列表?

c# - 数据库中有 1000 多个 Linq 查询或逻辑……哪个更糟?

c# - 您将如何重构此 LINQ 代码?

linq - 在 Linq2SQL 中,如何在单个查询中获取记录以及序列中的前一个和下一个?

c# - 在正确的时间恢复 GridView 上的滚动位置