EntityGraphShape.Edge ignoring collections?

Jul 6, 2011 at 6:30 AM

Hi,

I used the following statement to construct an EntityShapeGraph with RIA Services. Note that the first two properties (Sector and Owner) return single entities while the third and fourth (AssetAllocation and Option_Platform) return collections.

New EntityGraphShape().
	Edge(Of [Option], Sector)(Function(x) x.Sector).
	Edge(Of [Option], Owner)(Function(x) x.Owner).
	Edge(Of [Option], AssetAllocation)(Function(x) x.AssetAllocations).
	Edge(Of [Option], Option_Platform)(Function(x) x.Option_Platform)

I am finding that only the properties that return single entitites are being included in the EntityGraphShape. The documentation indicated that collection properties are supported through the Carpark example and the following EntityGraphShape and the edges related to Cars, Wheels and Doors.

new EntityGraphShape()
	.Edge<CarPark, Car>(CarPark => CarPark.Cars)
	.Edge<Car, Wheel>(Car => Car.Wheels)
	.Edge<Car, Door>(Car => Car.Doors)
            .Edge<Car, Engine>(Car => Car.Engine)
            .Edge<Truck, Trailer>(Truck => Truck.Trailer);
I guess that the problem is somewhere within the Edge method but don't see any obvious cause.
public EntityGraphShape Edge<TLHS, TRHS>(Expression<EdgeEnumType<TLHS, TRHS>> edge)
{
	Type type = edge.Parameters.Single<ParameterExpression>().Type;
	if (edge.Body as MemberExpression)
	{
		MemberExpression body = (MemberExpression)edge.Body;
		PropertyInfo member = body.Member as PropertyInfo;
		if (type != null && member != null)
		{
			this.edges.Add(new Tuple<Type, PropertyInfo>(type, member));
		}
	}
	return this;
}
Is there something that I am missing here?
Thanks,
Scott
 
Jul 7, 2011 at 4:08 AM

It looks as though this issue might be related to VB.Net. For EntityCollection properties, the lambda expression was being wrapped in a Convert expression. I will submit a patch with the fix that resolved the issue for me but basically, it involved using the following version of the Edge function in the EntityShapeGraph.shared.cs file. Note the conditional which checks whether the body of the edge is a UnaryExpression - if this is the case then it 'unwraps' it by extracting the operand.

        // We can't use TEntity as the return type of EdgeEnumType, because IEnumerable<T> is not 
        // covariant in Silverlight!!. Therefore a second type parameter TRHS is needed.
        public EntityGraphShape Edge<TLHS, TRHS>(Expression<EdgeEnumType<TLHS, TRHS>> edge)
        {
            var entityType = edge.Parameters.Single().Type;

            Expression body;

            if (edge.Body is UnaryExpression)
            {
                body = ((UnaryExpression)edge.Body).Operand;
            }
            else
            {
                body = edge.Body;
            }

            if(body is MemberExpression == false)
            {
                var msg = String.Format("Edge expression '{0}' is invalid; it should have the form 'A => A.B'", edge.ToString());
                throw new Exception(msg);
            }
            var mexpr = (MemberExpression)body;
            if(mexpr.Expression is ParameterExpression == false)
            {
                var msg = String.Format("Edge expression '{0}' is invalid; it should have the form 'A => A.B'", edge.ToString());
                throw new Exception(msg);
            }
            var propInfo = mexpr.Member as PropertyInfo;
            if(entityType != null && propInfo != null)
            {
                edges.Add(new EntityGraphEdge { FromType = entityType, EdgeInfo = propInfo });
            }
            return this;
        }
Developer
Aug 3, 2011 at 8:10 AM

Hi Scott,

Thanks a lot for sharing. I've just integrated your patch in EntityGraph (see chageset 64463).

Merijn