sebagomez
sebagomez

Reputation: 9609

Simplify this property to be used in a predicate

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)

Upvotes: 2

Views: 201

Answers (2)

Enigmativity
Enigmativity

Reputation: 117064

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.

Upvotes: 1

sebagomez
sebagomez

Reputation: 9609

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?

Upvotes: 0

Related Questions