我有充当DTO的实体类和代表表的域类,它们来自Entity Framework模型。我想创建一个从function Child(props) {
return <div {...props}>Hello</div>;
}
export default function Parent(props) {
return <Child {...props} />;
}
中使用的通用过滤器方法,但是我不想将实体框架模型类公开给控制器,我希望控制器仅处理DTO。
所以,我有这个通用方法:
Controller
但是,IEnumerable<Employee> Filter(Expression<Func<Employee, bool>> filter);
类的Employee
在表中具有DTO
类型的Status
枚举,它是System.Int32
类型的Status_id
列。
当我像这样使用此功能时:
int
我收到以下异常:
System.InvalidOperationException:不允许将子表达式从类型'Entities.Statuses'重写为类型'System.Int64',因为这会改变操作的含义。如果这是故意的,请覆盖“ VisitUnary”并将其更改为允许此重写。”
这是我正在使用的代码,请注意memberMapper是一个简单的return employeeRepository.Filter(
item => item.Age > 40 && item.StatusId != Statuses.Deleted);
,它将Func<string,string>
类属性的名称转换为与数据库表匹配的DTO
类属性名称列名。
EntityFramework
正在使用public static class PredicateMapper
{
public static Expression<Func<TTo, bool>> CastParameter<TFrom, TTo>(
this Expression<Func<TFrom, bool>> predicate, Func<string,string> memberMapper)
{
return new ParameterTypeVisitor<TFrom, TTo>(predicate, memberMapper).Transform();
}
}
class ParameterTypeVisitor<TSource, TDestination> : ExpressionVisitor
{
private readonly Expression<Func<TSource, bool>> _expression;
private readonly Func<string, string> _propertyMapper;
private readonly Dictionary<string, ParameterExpression> _parameters;
public ParameterTypeVisitor(Expression<Func<TSource, bool>> expression, Func<string,string> propertyMapper)
{
_parameters = expression.Parameters
.ToDictionary(p => p.Name, p => Expression.Parameter(typeof(TDestination), p.Name));
_expression = expression;
_propertyMapper = propertyMapper;
}
public Expression<Func<TDestination, bool>> Transform()
{
return (Expression<Func<TDestination, bool>>) Visit(_expression);
}
protected override Expression VisitMember(MemberExpression node)
{
var sourceType = typeof(TSource);
if (node.Member.DeclaringType == sourceType || IsExistOnBaseClass(sourceType.BaseType,node.Member.DeclaringType))
{
var memberName = node.Member.Name;
var destinationProperty = typeof(TDestination).GetProperty(_propertyMapper(memberName));
if (destinationProperty != null)
{
// Return Property from TDestination
var expression = Visit(node.Expression);
return Expression.MakeMemberAccess(expression, destinationProperty);
}
}
return base.VisitMember(node);
}
private bool IsExistOnBaseClass(Type type, Type typeToCheck)
{
if (type == null)
return false;
if (type == typeToCheck)
return true;
return IsExistOnBaseClass(type.BaseType, typeToCheck);
}
protected override Expression VisitParameter(ParameterExpression node)
{
var parameter = _parameters[node.Name];
return parameter;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
try
{
var expression = Visit(node.Body);
return Expression.Lambda(expression, _parameters.Select(x => x.Value));
}
catch (Exception e)
{
throw;
}
}
}
方法抛出异常。