2

I have many Accounts, each account can also have child accounts. So my way of knowing if an account is root is thanks to the value in the ParentId property.
So it turned out that my code has stuff like this in many places: .Where(acc => acc.ParentId == 0) so I thought about creating a property that looks like this:

public bool IsRootAccount
{
    return a.ParentId == 0;
}

It seems to work, it compiles, but when running I get the following exception:

Load operation failed for query 'GetAccounts'. The specified type member 'IsRootAccount' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Is there a simple way I can achieve what I want?

I also thought about creating something that would return an Expression<Func<Account, bool>> with no luck.

Edit: my attempt for the IsRootAccount property was in order to use something like this .Where(acc => acc.IsRootAccount)

sebagomez
  • 9,501
  • 7
  • 51
  • 89
  • 2
    The return type of `IsRootAccount` doesn't match the value that is returned (`bool` != lambda). – Kirk Woll Mar 09 '12 at 00:17
  • thanks, I fixed it... I copied it from a different property :) – sebagomez Mar 09 '12 at 00:26
  • Can you also show us the query you're trying to build that consumes this property? I doubt you can do exactly what you want here, but we might be able to suggest some alternative solutions. – Kirk Woll Mar 09 '12 at 00:31

2 Answers2

1

A very simple way to provide this functionality is using an extension method.

Try something like this:

public static class AccountEx
{
    public static IQueryable<Account> WhereIsRootAccount(
            this IQueryable<Account> source)
    {
        return source.Where(acc => acc.ParentId == 0);
    }
}

You then would replace every usage of .Where(acc => acc.ParentId == 0) with .WhereIsRootAccount().

The advantage with this approach is that it works with EF and it provides a fluent way to query your root accounts. If you need to modify the definition of a root account you also only have one place to make the change. And it doesn't pollute your Account class with unnecessary code.

I hope this helps.


Based on your comment, try this:

public static class AccountEx
{
    public static EntityQuery<Account> WhereIsRootAccount(
            this EntityQuery<Account> source)
    {
        return source.Where(acc => acc.ParentId == 0);
    }
}

Since Where is supported by EntityQuery<> then it should still work fine.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • I love the idea... will give it a try – sebagomez Mar 09 '12 at 12:03
  • It does help, thanks... but it can't be used from the Silverlight client, right? is there a way of doing that on the client side? – sebagomez Mar 09 '12 at 12:12
  • @sebastian - I'm not totally up on Silverlight - can you tell me why you don't think this'll work from Silverlight? – Enigmativity Mar 09 '12 at 12:25
  • because the RIA service that expose my data exposes my return values as `EntityQuery` which is exclusively from the Silverlight framework... http://msdn.microsoft.com/en-us/library/system.servicemodel.domainservices.client.entityquery(v=vs.91).aspx – sebagomez Mar 09 '12 at 12:34
  • @sebastian - Please see my modified answer. – Enigmativity Mar 10 '12 at 05:50
  • 1
    yes, that's what I thought and it works but I must have two identical methods, one for the server side and the later for the client side... I guess that's the only way – sebagomez Mar 10 '12 at 12:18
0

Here's something I found but I would like to see if there's anything better to do.
I understand EF does not know how to transform my predicate to SQL because of my property. So I can't do this:

Context.Load(Context.GetAccountsQuery().Where(acc => acc.IsRootAccount), ParentAccountsArrived, null);  

but I do can filter with my property once the results are back from the server:

public void LoadParentAccounts()
{
    Context.Load(Context.GetAccountsQuery(), ParentAccountsArrived, null);  
}
void ParentAccountsArrived(LoadOperation<Account> lo)
{
    foreach (var account in lo.Entities.Where(acc => acc.IsRootAccount))
    {
        ParentAccounts.Add(account.Name);
    }
}   

Is this the way to go? Is there a performance issue with this change?

sebagomez
  • 9,501
  • 7
  • 51
  • 89