New Posts New Posts RSS Feed: Server side query for nested entities - expression instead of string
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Server side query for nested entities - expression instead of string

 Post Reply Post Reply
Author
zbig View Drop Down
Newbie
Newbie
Avatar

Joined: 13-Oct-2012
Posts: 28
Post Options Post Options   Quote zbig Quote  Post ReplyReply Direct Link To This Post Topic: Server side query for nested entities - expression instead of string
    Posted: 07-Sep-2013 at 2:34pm
Is it possible to use expression instead of string with nested entities,
for example:

var usersQuery = entityManager.GetQuery<User>()
.Include(ur => ur.UserRoles)
.Include(ur => ur.UserRoles.Select(r => r.Role))

instead of:

var usersQuery = entityManager.GetQuery<User>()
.Include(ur => ur.UserRoles)
.Include("UserRoles.Role")

This first "style" I have previously used in onother project but with DF it does not work (parsing error ...).


Back to Top
sbelini View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 13-Aug-2010
Location: Oakland
Posts: 786
Post Options Post Options   Quote sbelini Quote  Post ReplyReply Direct Link To This Post Posted: 09-Sep-2013 at 2:48pm
Hi Zbig,

In the situation where you are including entities related to entities in a RelatedEntityList, the option is to use the string parameter.

If including entities related to one entity, then you can use lambda and .PathFor as well.

Note that you cannot use .Select.

You will find more information on including related entities at http://drc.ideablade.com/devforce-2012/bin/view/Documentation/include-related-entities.
Back to Top
cefernan View Drop Down
Groupie
Groupie


Joined: 13-Jul-2012
Posts: 70
Post Options Post Options   Quote cefernan Quote  Post ReplyReply Direct Link To This Post Posted: 10-Sep-2013 at 7:12am
Zbig,

Instead of use strings and to prevent runtime error, I've created these extensions methods:
public static IFetchOptions<T> Include<T>(this IFetchOptions<T> source, params string[] attachedPropertyPaths)
{
    return source.Include(IncludeHelper.GetPropertyPath(attachedPropertyPaths));
}
 
public static IFetchOptions<T> Include<T>(this IFetchOptions<T> source, Expression<Func<T, object>> expr, params string[] attachedPropertyPaths)
{
    return source.Include(IncludeHelper.GetPropertyPath(expr, attachedPropertyPaths));
}
How to use:
IncludeExpression = c => c.Include(f => f.FilterCategory)
    .Include(f => f.FilterOperatorClauses)
    .Include(f => f.FilterOperatorClauses, FilterOperatorClause.EntityPropertyNames.FilterConditions)
    .Include(f => f.FilterOperatorClauses, FilterOperatorClause.EntityPropertyNames.FilterConditions, FilterCondition.EntityPropertyNames.FilterConditionValues)
I hope this may help you.
Back to Top
cefernan View Drop Down
Groupie
Groupie


Joined: 13-Jul-2012
Posts: 70
Post Options Post Options   Quote cefernan Quote  Post ReplyReply Direct Link To This Post Posted: 10-Sep-2013 at 7:13am
    public static class IncludeHelper
    {
        public static string GetPropertyPath<T>(Expression<Func<T, object>> expr, params string[] attachedPropertyPaths)
        {
            // Build path list
            var body = expr.Body;
            var pathList = new List<string>();
            while (body != null && body.NodeType == ExpressionType.MemberAccess)
            {
                var memberBody = (MemberExpression)body;
                pathList.Insert(0, memberBody.Member.Name);
 
                if (memberBody.Expression.NodeType == ExpressionType.MemberAccess)
                    body = memberBody.Expression;
                else
                    body = null;
            }
 
            // Add path includes to path list
            if (attachedPropertyPaths != null)
                pathList.AddRange(attachedPropertyPaths);
 
            // Build property path
            return String.Join(".", pathList);
        }
 
        public static string GetPropertyPath(params string[] attachedPropertyPaths)
        {
            return String.Join(".", attachedPropertyPaths);
        }
    }
Back to Top
stephenmcd1 View Drop Down
DevForce MVP
DevForce MVP


Joined: 27-Oct-2009
Location: Los Angeles, CA
Posts: 166
Post Options Post Options   Quote stephenmcd1 Quote  Post ReplyReply Direct Link To This Post Posted: 10-Sep-2013 at 10:47am
I've built a helper class that builds strings such as 'UserRoles.Role' using strongly typed lambdas.  It's not always the easiest to use but it gets the job done.  And for us, a little bit of annoyance/verbosity when first writing the code is worth it if it saves of from running into problems if the model changes.  An example usage of the helper class would be:
    [TestMethod]
    public void TestBuildPath()
    {
        var actualPath = IncludeHelper
            .BuildPathFor<User>()
            .IncludeMany(user => user.UserRoles)
            .Include(userRole => userRole.Role)
            .ToString();

        Assert.AreEqual("UserRoles.Role", actualPath);

    }

In this case, the IncludeMany method is the one that is really giving us value because it lets us 'flatten' the collection.

You can get the full code from here:  https://gist.github.com/stephenmcd1/5586462

Note: A very similar question was asked before.  This answer is almost identical to the one I posted there.
Back to Top
zbig View Drop Down
Newbie
Newbie
Avatar

Joined: 13-Oct-2012
Posts: 28
Post Options Post Options   Quote zbig Quote  Post ReplyReply Direct Link To This Post Posted: 10-Sep-2013 at 1:15pm
@sbelini - thanks for the suggestion, good to know, that "PathFor" clause exists.

@cefernan, @stephenmcd1 - thanks for inspiring solutions!
Unfortunatelly I can't use the first one, because I'm not using Cocktail (no IFetchOptions).
I have tried the second one and it works great!

Thanks a lot!
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down