【发布时间】:2015-02-07 20:26:33
【问题描述】:
我正在将 Expression<T, bool> 转换为 Expression<Y, bool>,其中 T 和 Y 是不同的实体,除了通过 Automapper 映射之外,没有任何关联。本质上,我有一个我的代码使用的模型对象:
public class Store
{
public string StoreId { get; set; }
public string Name { get; set; }
public List<Phone> Phones { get; set; }
public Address Address { get; set; }
public Account Account { get; set; }
public Status Status { get; set; }
}
我正在映射到一个实体对象以存储在我的 mongo 数据库中:
public class Store : MongoEntity
{
public string AccountId { get; set; }
public string Name { get; set; }
public List<string> UserIds { get; set; }
public List<Phone> PhoneNumbers { get; set; }
public Address Address { get; set; }
}
public abstract class MongoEntity : IMongoEntity
{
[BsonId]
public ObjectId Id { get; set; }
public Status Status { get; set; }
}
我使用这个问题中的答案来计算如何在表达式之间进行转换 (Question),这让我达到了 90%。我能够修改代码以获取模型存储和实体存储之间的 AutoMapper 映射,并从源属性中获取目标属性:
private Expression<Func<TNewTarget, bool>> TransformPredicateLambda<TOldTarget, TNewTarget>(
Expression<Func<TOldTarget, bool>> predicate)
{
var lambda = (LambdaExpression)predicate;
if (lambda == null)
{
throw new NotSupportedException();
}
//Modified here to get automapper mappings
var maps = Mapper.FindTypeMapFor<TOldTarget, TNewTarget>();
var mutator = new ExpressionTargetTypeMutator(t => typeof(TNewTarget), maps);
var explorer = new ExpressionTreeExplorer();
var converted = mutator.Visit(predicate.Body);
return Expression.Lambda<Func<TNewTarget, bool>>(
converted,
lambda.Name,
lambda.TailCall,
explorer.Explore(converted).OfType<ParameterExpression>());
}
protected override Expression VisitMember(MemberExpression node)
{
var dataContractType = node.Member.ReflectedType;
var activeRecordType = _typeConverter(dataContractType);
PropertyMap prop = null;
foreach (var propertyMap in _maps)
{
var source = propertyMap.SourceMember;
var dest = propertyMap.DestinationProperty;
if (source != null && source.Name == node.Member.Name)
{
prop = propertyMap;
}
}
if (prop == null)
{
return base.VisitMember(node);
}
var propertyName = prop.DestinationProperty.Name;
var property = activeRecordType.GetProperty(propertyName);
var converted = Expression.MakeMemberAccess(
base.Visit(node.Expression),
property
);
return converted;
}
问题是,我的实体对象与我的模型对象没有所有相同的属性(例如,Account 对象与 AccountId)。当 Transformer 到达 Model 对象上的 Account 属性时,我得到一个异常(因为我的 Entity 对象上没有匹配的属性)。我无法从 VisitMember 返回 null,也不允许使用 new Expression()。如何处理忽略我的实体对象上不存在的模型对象上的属性?
使用评论中的信息进行更新
所以,为了更清楚一点,我使用 Automapper 从 Models.Store 映射到 Entity.Store。我的 entity.Store 只有一个 AccountId(因为我不想复制所有帐户数据),但我的 Models.Store 需要整个帐户对象(我可以通过查询 Accounts 集合获得)。
Automapper 基本上将我的 Account 对象转换为我实体上的 AccountId。因此,当我搜索x => x.Account.AccountId == abcd1234(其中x 是models.Store)时,我需要将我的表达式转换为x => x.AccountId == abcd1234(其中x 是Entity.Store)。
我有这部分工作(将mS => mS.Account.AccountId == 1234 更改为mE => mE.AccountId == 1234)。我现在遇到的问题是,在完成 AccountId 属性之后,以 Account 作为节点调用了 VisitMember。由于我的 Entity.Store 对象中没有 Account,我得到了异常。
【问题讨论】:
-
问题的链接不能正常工作,我想是this one =)
-
对不起这位大师,我更新了链接。
-
你如何忽略
A在谓词x => x.A == 1中不存在的事实? -
我试图做 x=> x.Account.AccountId==... 我找到了 AccountId 的正确属性,但随后它试图找到 Account(不存在)
-
所以,为了更清楚一点,我使用 Automapper 从 Models.Store 映射到 Entity.Store。我的 entity.Store 只有一个 AccountId(因为我不想复制所有的帐户数据),但我的 Models.Store 需要整个帐户对象(我可以通过查询 Accounts 集合获得)。 Automapper 基本上将我的 Account 对象转换为我实体上的 AccountId。因此,当我搜索 x => x.Account.AccountId == abcd1234(其中 x 是 models.Store)时,我需要将表达式转换为 x => x.AccountId(其中 x 是 Entity.Store)。 ...
标签: c# linq lambda expression-trees