Search code examples
linqasp.net-mvc-5linq-to-entitieslinq-expressions

"LINQ to Entities does not recognize the method 'Boolean ***, and this method cannot be translated into a store expression."


I am coding a MVC 5 internet application, and am getting the following error:

base = {"LINQ to Entities does not recognize the method 'Boolean IsAccountSetupForSendingFreeTrialSubscriptionExpirationEmail(CanFindLocation.Models.Account)' method, and this method cannot be translated into a store expression."}

Here are my methods:

public IEnumerable<Account> GetFreeTrialAccountsForSendDailyExpirationEmails(int minimumDaysLeftInSubscriptionForEmail)
{
    IEnumerable<Account> freeTrialAccounts = genericMultipleRepository.accounts.Value.SearchFor(a => IsAccountSetupForSendingFreeTrialSubscriptionExpirationEmail(a) && ShouldDailyExpirationEmailBeSentForFreeTrialAccount(a, minimumDaysLeftInSubscriptionForEmail));
    return freeTrialAccounts;
}

public bool IsAccountSetupForSendingFreeTrialSubscriptionExpirationEmail(Account account)
{
    if (account.isFreeTrial && account.sendSubscriptionExpirationEmail)
    {
        return true;
    }
    else
    {
        return false;
    }
}

public bool ShouldDailyExpirationEmailBeSentForFreeTrialAccount(Account account, int minimumDaysLeftInSubscriptionForEmail)
{
    if (IsExpiresDateTimeLessThanMinimumDaysLeftInFreeTrialSubscription(account, minimumDaysLeftInSubscriptionForEmail) && !HasSubscriptionEmailBeenSentForCurrentFreeTrialEndDateTime(account))
    {
        return true;
    }
    else
    {
        return false;
    }
}

public bool IsExpiresDateTimeLessThanMinimumDaysLeftInFreeTrialSubscription(Account account, int minimumDaysLeftInSubscriptionForEmail)
{
    TimeSpan expires = account.freeTrialEndDate - DateTime.UtcNow;
    return expires.Days < minimumDaysLeftInSubscriptionForEmail;
}

public bool HasSubscriptionEmailBeenSentForCurrentFreeTrialEndDateTime(Account account)
{
    return account.subscriptionEndDateForExpirationEmail == account.freeTrialEndDate;
}

My Account object has the following fields:

public bool isFreeTrial { get; set; }
public bool sendSubscriptionExpirationEmail { get; set; }
public DateTime subscriptionEndDateForExpirationEmail { get; set; }
public DateTime freeTrialEndDate { get; set; }

I have done some research, and I gather that the code that I have written cannot be converted into a LINQ expression.

What do I need to do to convert my code into a valid form so that the LINQ to Entities does not perform the error?

Thanks in advance.


Solution

  • You cannot refactor LinqToXXX queries into methods.

    For example.

    IQueryable<Foo> foos = ...;
    IQueryable<Foo> results = from f in foos
                              where f.IsBar
                              select f;
    

    Results in VASTLY different IL than

    IQueryable<Foo> foos = ...;
    IQueryable<Foo> results = from f in foos
                              where FooIsBar(f)
                              select f;
    
    
    public bool FooIsBar(Foo foo)
    {
        return foo.IsBar;
    }
    

    The latter will try to pass off FooIsBar to EntityFramework to "convert". Since EntityFramework does not have access to the source code at this point, it can't do the conversion of compiled IL code into SQL.

    The alternative is the following...

    IQueryable<Foo> foos = ...;
    IQueryable<Foo> results = from f in foos.Where(FooIsBar)
                              select f;
    
    
    public Expression<Func<Foo, bool>> FooIsBar
    {
        get { return foo => foo.IsBar; }
    }