我正在尝试将参数自动生成为IQueryable.Where所以我可以从我的实体框架代码第一个数据上下文中选择实体,而无需编写和连接大量繁琐的映射代码。
我的项目包含一堆看似如下的DTO: -
class FooDto
{
public string SomeProperty { get; set; }
public string SomeOtherProperty { get; set; }
}
一堆看似如下的实体: -
class Foo
{
public string SomeProperty { get; set; }
public string SomeOtherProperty { get; set; }
// Some other properties here.
}
DTO包含识别数据库中某些实体子集所必需的字段。我使用DTO来查询IQueryable实体: -
var result = queryable.Where(
x => x.SomeProperty == dto.SomeProperty
&& x.SomeOtherProperty == dto.SomeOtherProperty)
实际属性各不相同,但查询的形状始终为“其中实体上的所有属性都与DTO上的所有匹配属性匹配”。没有更复杂的查询对象功能。
有许多DTO和实体。创建/维护和连接所有这些谓词是一个具有挑战性的架构问题。我们目前正在使用策略模式: -
public class FooDtoSelectStrategy : ISelectStrategy<FooDto, FooEntity>
{
public Func<FooEntity, bool> GetPredicate(FooDto dto)
{
return x => x.SomeProperty == dto.SomeProperty
&& x.SomeOtherProperty == dto.SomeOtherProperty;
}
}
除了一堆ninject绑定之外,我们已经有几十个这样的绑定,随着我们的域扩展,我们还会看到数百个。
我们有一个类似的挑战,将实体到DTO的值映射到我们使用AutoMapper解析的。
自动播放器(或类似工具)可以创建这些谓词并允许我们实现单个GenericPredicateProvider<TDto, TEntity>
吗?
答案 0 :(得分:0)
您正在做的事实上被称为specification pattern。所以你基本上已经重新设计了车轮,想出了一个基本相同的车轮。
您可以使用类似T4模板的东西来自动生成这些谓词提供程序,但是您查询同一对象的对象似乎有点愚蠢。你已经拥有了这个对象,那你为什么要查询所有字段呢?
答案 1 :(得分:0)
<强>更新: - 强>
这是我的原型使用AutoMapper的类型映射来处理简单的情况。如果我想让它处理,例如,它将需要更多的工作。复杂的类型映射,但现在这是在做这项工作。
internal class AutoMapperSelectStrategy<TEntity, TIdentity> :
IIdentitySelectStrategy<TEntity, TIdentity>
{
private IMappingEngine mappingEngine;
internal AutoMapperSelectStrategy(
IMappingEngine<TEntity, TIdentity> mappingEngine)
{
this.mappingEngine = mappingEngine;
}
public Expression<Func<TEntity, bool>> GetPredicateForIdentity(
TIdentity identity)
{
var entityParameter = Expression.Parameter(typeof(TEntity));
var identityScope = Expression.MakeMemberAccess(
Expression.Constant(
new ExpressionScope<TIdentity>() { Value = identity }),
typeof(ExpressionScope<TIdentity>).GetProperty("Value"));
var equalityExpressions = this.MakeEqualityExpressions(
identityScope, entityParameter);
var aggregateEquality = equalityExpressions.Aggregate(
(x, y) => Expression.AndAlso(x, y));
var predicate = Expression.Lambda<Func<TEntity, bool>>(
aggregateEquality, entityParameter);
return predicate;
}
public IEnumerable<BinaryExpression> MakeEqualityExpressions(
MemberExpression identityScope, ParameterExpression entityParameter)
{
var mapExpression =
mappingEngine.CreateMapExpression<TIdentity, TEntity>();
var body = mapExpression.Body as MemberInitExpression;
var bindings = body.Bindings;
foreach (var binding in bindings.OfType<MemberAssignment>())
{
var memberExpression = binding.Expression as MemberExpression;
var left = Expression.Property(
identityScope, memberExpression.Member as PropertyInfo);
var right = Expression.Property(
entityParameter, binding.Member as PropertyInfo);
var equalityExpression = Expression.Equal(left, right);
yield return equalityExpression;
}
}
private class ExpressionScope<TDto>
{
public TDto Value { get; set; }
}
}