Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#相互转换谓词_C#_Linq_Linq To Sql_Predicate - Fatal编程技术网

c#相互转换谓词

c#相互转换谓词,c#,linq,linq-to-sql,predicate,C#,Linq,Linq To Sql,Predicate,我正在开发多层应用程序解决方案,我的解决方案如下 Business.DomainObject Business.Process(*实际业务层) 数据映射器 数据仓库 Data.Sql.Entity(*具有.dbml文件的实际数据层) 我的Business.Process项目(业务层)只知道Business.DomainObject和Data.Repository项目,因此不知道也不与Data.Sql.Entity项目相关 我将业务(域)对象发送到存储库,并在这个项目中进行映射,然后在存储库

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

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

一切正常,但我的“谓词”查询有一些问题。 我的存储库界面中有一个方法

bool IsExists(Expression<Func<BusinessObject,bool>> predicate);
bool-IsExists(表达式谓词);
并像这样在我的业务层中使用它

Repository r = new UserRepository(); <br/>
r.IsExists(p => p.Email.Equals("email address"));
Repository r=newuserrepository()
r、 iExists(p=>p.Email.Equals(“电子邮件地址”);
正如您所看到的,它的参数是“businessobject”,但我的实际存储库(与数据库连接)使用的是dbml文件中的“dataobject”。

public override bool IsExists(表达式谓词){
返回_table.Where(谓词).Any();
}
我要转换这两个谓词, 例如,我将发送UserBO并转换为UserDataObject


我该怎么做呢?

您必须分析LambdaExpression的参数和主体,然后构建一个新的。您可以使用predicate.body访问主体,并使用predicate.parameters访问参数。新表达式的参数类型为UserBO,而不是UserDataObject。此外,正文中的ParameterExpression必须使用新参数。
当然,这是假设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();
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Linq.Expressions;
使用系统文本;
名称空间转换表达式
{
公共类BusinessObject
{
公共int值{get;set;}
}
公共类数据对象
{
公共int值{get;set;}
}
内部类ExpressionConverter:ExpressionVisitor
{
公共表达式转换(表达式表达式转换)
{
回访(expr);
}
私有参数expression replaceParam;
受保护的重写表达式VisitLambda(表达式节点)
{
if(typeof(T)=typeof(Func))
{
replaceParam=Expression.Parameter(typeof(DataObject),“p”);
返回表达式.Lambda(Visit(node.Body),replaceParam);
}
返回base.VisitLambda(节点);
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
if(node.Type==typeof(BusinessObject))
return replaceParam;//Expression.Parameter(typeof(DataObject),“p”);
返回基本访问参数(节点);
}
受保护的重写表达式VisitMember(MemberExpression节点)
{
if(node.Member.DeclaringType==typeof(BusinessObject))
{
var member=typeof(DataObject).GetMember(node.member.Name,System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).FirstOrDefault();
if(成员==null)
抛出新的InvalidOperationException(“无法识别数据对象的对应成员”);
返回Expression.MakeMemberAccess(访问(node.Expression),成员);
}
返回base.VisitMember(节点);
}
}
公共类表达式
{
公共静态void Main()
{
BusinessObject[]bos={new BusinessObject(){Value=123},new BusinessObject(){Value=246};
DataObject[]dos={newdataobject(){Value=123},newdataobject(){Value=246};
表达式boExpr=x=>x.Value==123;
var conv=new ExpressionConverter();
表达式doExpr=(表达式)conv.Convert(boExpr);
var selBos=bos.Where(boExpr.Compile());
WriteLine(“匹配的BusinessObjects:{0}”,selBos.Count());
foreach(selBos中的var bo)
控制台写入线(bo.Value);
var compDoExpr=doExpr.Compile();
var selDos=dos.Where(doExpr.Compile());
WriteLine(“匹配的数据对象:{0}”,selDos.Count());
foreach(selDos中的var dataObj)
Console.WriteLine(数据对象值);
Console.ReadLine();
}
}
}

您的代码可以很好地处理单个属性,如

Repository.IsExists(p => p.Email.Equals("abc@xyz.com"));
但正如我所提到的,当我尝试这样做时,我的域对象类有一些嵌套的类属性,比如“City”

Repository.IsExists(p => p.City.Id.Equals(city id));
它抛出一个异常

财产 'Business.DomainObject.SystemCommon.ExtendedProperty.PrimaryKey 未为类型定义“Id” 'Data.Sql.Entity.LinqDataContext.City'

我理解这个例外,因为我的城市班是这样的

public class CityBO : IDomainObject
{
  public PrimaryKey Id { get; set; }
  public string Name { get; set; }
  public EntityReferance<CountryBO> Country { get; set; }
  public LocationInfoBO Location { get; set; }
  public StatusInfo Status { get; set; }  
}
我正在使用这个属性,因为我的实体有不同的主键类型,而且我正在计划将来实现Nosql db

我想感谢您的代码,当我查询单个属性时,它对我很有用


关于

如果需要,我创建了一个小的fluent库来创建lambda f
public class CityBO : IDomainObject
{
  public PrimaryKey Id { get; set; }
  public string Name { get; set; }
  public EntityReferance<CountryBO> Country { get; set; }
  public LocationInfoBO Location { get; set; }
  public StatusInfo Status { get; set; }  
}
public class PrimaryKey
{
  public string Value { get; set; }
}
//Cached somewhere
var compareLambda= ExpressionUtil.GetComparer<CityBO>(p => 
  p.Id.Value,ComparaisonOperator.Equal);

//Then in the execution
Repository.IsExists(p=>compareLambda(p,city id));
internal class ExpressionConverter<TInput, TOutput> : ExpressionVisitor
{
    public Expression<Func<TOutput, bool>> Convert(Expression<Func<TInput, bool>> expression)
    {
        return (Expression<Func<TOutput, bool>>)Visit(expression);
    }

    private ParameterExpression replaceParam;

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

    protected override Expression VisitParameter(ParameterExpression node)
    {
        if (node.Type == typeof(TInput))
            return replaceParam;
        return base.VisitParameter(node);
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Member.DeclaringType == typeof(TInput))
        {
            var member = typeof(TOutput).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);
    }
}