我正在开发多层应用程序解决方案,我的解决方案如下所示
- Business.DomainObject
- Business.Process(*实际业务层)
- 数据映射器
- 数据存储库
- Data.Sql.Entity(* 具有 .dbml 文件的实际数据层)
我的Business.Process项目(业务层)只知道Business.DomainObject和Data.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/