4

Related vaguely to a previous question

Note : I'm using a derivative of the ExpressionTree visitor as explained here

In my VisitMemberAccess method I currently create MemberExpressions using something along the lines of:

// `mapping` is a class used to map EntityA's members to EntityB's members
return Expression.MakeMemberAccess(Visit(m.Expression), mapping.TargetMemberInfo);

For the most part, this works.

Given some test classes...

public class EntityA
{
    public long Id { get; set; }
    public string Name { get; set; }
}

public class EntityB
{
    public long MyId {get; set; }
    public string MyName { get; set; }
}

The code will correctly map (EntityA x) => x.Id to (EntityB x) => x.MyId which is great and works lovely. My problem comes when you introduce navigation properties:

public class EntityB
{
    public long MyId {get; set; }
    public EntityBDetails NavigationProperty { get; set; }
}    

public class EntityBDetails
{
    public string MyName { get; set; }
}

Given the above trivial case, I would want (EntityA x) x => x.Name to map to (EntityB x) x => x.NavigationProperty.Name. And therelies the problem, I have no idea what to supply to MakeMemberAccess to make this work... I can compare mapping.TargetMemberInfo.DeclaringType == mapping.TargetMemberInfo.ReflectedType to determine whether there is a navigation property involved, but how do I create the necessary MemberExpression?

Thanks in advance!

NB: The code base I'm working on is VB; C# tends to get better/faster answers on SO so I've converted by hand. Let me know if I've made silly typo's/etc

Community
  • 1
  • 1
Smudge202
  • 4,689
  • 2
  • 26
  • 44
  • I've just found [this question](http://stackoverflow.com/questions/307512/how-do-i-apply-orderby-on-an-iqueryable-using-a-string-column-name-within-a-gener) - the [answer by Davy Landman](http://stackoverflow.com/questions/307512/how-do-i-apply-orderby-on-an-iqueryable-using-a-string-column-name-within-a-gener/308863#308863) looks like it contains what I need - need to go away and factor it in. Will update. – Smudge202 Sep 07 '11 at 13:43

1 Answers1

12

I think it could help to translate the C# code into English, and then translate that into an expression-creating code:

The expression x.NavigationProperty.Name actually means “access property NavigationProperty on x and then access property Name on the result. Now, the code:

ParameterExpression x = …;
var navigationProperty = typeof(EntityB).GetProperty("NavigationProperty");
var name = typeof(EntityBDetails).GetProperty("Name");

var navigationPropertyAccess = Expression.MakeMemberAccess(x, navigationProperty);
var nameAccess = Expression.MakeMemberAccess(navigationPropertyAccess , name);
svick
  • 236,525
  • 50
  • 385
  • 514
  • -1 I'm all for constructive critiscm and being corrected but `"I think it could help to translate the C# code into English"` seems a little more like mocking to me... perhaps I've misread your statement? The reason I called it "Navigation Property" is because that is what it is referred to in [Entity Framework](http://msdn.microsoft.com/en-us/library/bb738520.aspx) which is the ORM I'm using... – Smudge202 Sep 07 '11 at 22:32
  • 3
    I didn't mean it as mocking. It looked like you didn't get the point that you have to use `MakeMemberAccess()` twice, since you have two property accesses in the expression you want to create. I know you know what the expression does. But I think it can be useful to stop and think what it actually means, by translating the C# into English. And I didn't comment about the naming, so I'm not sure why you mentioned it. – svick Sep 07 '11 at 22:52
  • You're right, I hadn't realised I needed to call `MakeMemberExpression` multiple times until I read the answer on the question I linked in the comments above. I think I understand the context of the aforementioned statement now. Feel free to make a minor edit and I'll remove the -1. Thanks for the answer – Smudge202 Sep 07 '11 at 23:31